soma.cell

E0030: ws_placement

E0030 ws_placement — on ws outside the cell that owns request.

A compile-time error of soma check, the checker of the Soma programming language (soma explain E0030).

The rule

soma serve routes WebSocket frames only to the cell that owns on request, so an on ws in any other cell would never run; soma check reports it. Put on ws(msg: String) in the request-owning cell and delegate to the domain cell from there. The same code is used when on ws takes something other than a String: a frame arrives as text, parsed with from_json(msg).

A program that triggers it

wrong.cell

cell Api {
    on request(method: String, path: String, body: String) {
        return response(404, map("error", "not found"))
    }
}

cell Chat {
    memory {
        messages: List<String> [persistent]
    }
    on ws(msg: String) {
        messages.push(msg)
        publish("chat", msg)
    }
}

What soma check prints:

$ soma check wrong.cell
error: `on ws` of cell Chat never runs: `soma serve` serves the cell that owns `request` (Api) — move `on ws` there
  --> wrong.cell:11:5
   |
11 |     on ws(msg: String) {
   |     ^
  = code: E0030
✗ 1 error(s), 0 warning(s).

The fix field of soma check --json: move `on ws` there

3 lines are added after line 3; on line 11, on ws(msg: String) { becomes on post(msg: String) {.

wrong.cell → right.cell

--- wrong.cell
+++ right.cell
@@ -2,4 +2,7 @@
     on request(method: String, path: String, body: String) {
         return response(404, map("error", "not found"))
+    }
+    on ws(msg: String) {
+        Chat.post(msg)
     }
 }
@@ -9,5 +12,5 @@
         messages: List<String> [persistent]
     }
-    on ws(msg: String) {
+    on post(msg: String) {
         messages.push(msg)
         publish("chat", msg)

With the fix, soma check accepts the program:

$ soma check right.cell
✓ All checks passed.