ruvnet/RuView · error · ValueError
sensing-server emitted non-dict payload: {type(obj).__name__
Error message
sensing-server emitted non-dict payload: {type(obj).__name__} What it means
_decode() in ws.py JSON-parses each websocket frame and requires the root to be a dict — the sensing-server protocol is a stream of JSON objects keyed by "type". A frame whose JSON root is an array, string, number, or bool violates the protocol and raises ValueError. stream() catches this per-frame and logs a WARN, but recv_one() lets the ValueError propagate to the caller.
Source
Thrown at python/wifi_densepose/client/ws.py:142
node_id: str = ""
timestamp: float = 0.0
persons: tuple[dict[str, Any], ...] = ()
confidence: float = 0.0
# ─── Decoder ─────────────────────────────────────────────────────────
def _decode(raw_text: str) -> SensingMessage:
"""Decode a single WS frame into a typed message.
Unknown ``type`` values yield a plain ``SensingMessage`` rather
than raising — the sensing-server is on a faster release cadence
than this client, and unknown types should not break the stream.
"""
obj = json.loads(raw_text)
if not isinstance(obj, dict):
raise ValueError(f"sensing-server emitted non-dict payload: {type(obj).__name__}")
mtype = obj.get("type", "")
if mtype == "connection_established":
return ConnectionEstablishedMessage(
type=mtype,
raw=obj,
node_id=obj.get("node_id", ""),
version=obj.get("version", ""),
capabilities=tuple(obj.get("capabilities", ())),
)
if mtype == "edge_vitals":
return EdgeVitalsMessage(
type=mtype,
raw=obj,
node_id=obj.get("node_id", ""),
presence=bool(obj.get("presence", False)),
fall_detected=bool(obj.get("fall_detected", False)),
motion=float(obj.get("motion", 0.0)),
breathing_rate_bpm=(View on GitHub (pinned to 4685618388)
Solutions
- Use stream() instead of recv_one() — it logs and drops malformed frames without ending the iteration
- Verify the URL targets the sensing-server's /ws/sensing endpoint and the server version matches the client
- Fix custom/mock servers to emit top-level JSON objects with a "type" field
Example fix
# before
msg = await client.recv_one() # ValueError: sensing-server emitted non-dict payload
# after
async for msg in client.stream(): # malformed frames are logged and skipped
if isinstance(msg, EdgeVitalsMessage):
process(msg) Defensive patterns
Strategy: try-catch
Try / catch
while True:
try:
msg = await client.recv_one(timeout=5.0)
except ValueError as e:
log.warning("dropping malformed sensing frame: %r", e)
continue # skip this frame, keep the connection
except asyncio.TimeoutError:
break Prevention
- Prefer stream() for continuous consumption — it already isolates per-frame decode errors
- Pin client and sensing-server versions together in deployment
- Contract-test custom/mock servers to emit top-level JSON objects with a type field
When it happens
Trigger: Awaiting recv_one() when the server sends a frame like `[1,2,3]` or `"ok"`; pointing SensingClient at the wrong endpoint or a mock server that emits JSON arrays / bare values instead of objects.
Common situations: Version skew between client and sensing-server; a test mock returning json.dumps(list); connecting to a non-sensing route that streams JSONL arrays.
Related errors
- brain line ${index + 1}: ${error.message}
- Invalid stream options: ${validationResult.errors.join(', ')
- Failed to load domain configuration: {e}
- {path}: expected {{'nodes': [...]}} or a top-level list
- {path}: each node needs 'id' and 'position_m' [x,y,z]
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/44e5662ed6090eed.
Report an issue: GitHub.