{"record":{"id":"1deab690bb4b972e","repo":"sgl-project/sglang","slug":"kind-transition-actions-must-be-a-list","errorCode":null,"errorMessage":"{kind} transition actions must be a list","messagePattern":"(.+?) transition actions must be a list","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/realtime/control_signals.py","lineNumber":127,"sourceCode":"\n\ndef _control_state_transitions_from_event_payload(\n    payload: dict[str, Any],\n    *,\n    event_id: int | None,\n    kind: str,\n    normalize_state_payload: ControlStatePayloadNormalizer,\n) -> list[ControlStateTransition]:\n    transitions = payload.get(\"transitions\")\n    if not isinstance(transitions, list):\n        raise ValueError(f\"{kind} state payload requires transitions\")\n    result = []\n    for transition in transitions:\n        if not isinstance(transition, dict):\n            raise ValueError(f\"{kind} transition must be a map\")\n        actions = transition.get(\"actions\")\n        if not isinstance(actions, list):\n            raise ValueError(f\"{kind} transition actions must be a list\")\n        timestamp_ms = transition.get(\"client_ts_ms\")\n        if timestamp_ms is not None:\n            timestamp_ms = int(timestamp_ms)\n        result.append(\n            ControlStateTransition(\n                payload=normalize_state_payload(actions),\n                seq_id=event_id,\n                timestamp_ms=timestamp_ms,\n            )\n        )\n    return result\n\n\nclass ControlSignalQueue:\n    \"\"\"FIFO storage for discrete realtime control signals\n\n    Script-mode controls and one-shot signals are already expressed as discrete\n    payloads, so sampling only consumes queued signals and applies the requested","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/realtime/control_signals.py#L109-L145","documentation":"Raised while parsing a control-state event payload: each transition in the event's transitions list must itself carry an `actions` key whose value is a JSON list. The parser (called from parse_control_event_payload) refuses anything else so downstream normalize_state_payload always receives a list.","triggerScenarios":"Calling parse_control_event_payload with a payload where transitions[i]['actions'] is missing, null, a dict, or a string instead of a JSON array.","commonSituations":"Upstream producer changes the control-event schema (actions renamed, emitted as an object map keyed by action name); hand-crafted test payloads omitting actions; JSON where actions is null.","solutions":["Fix the producer of the control event so each transition's actions is a JSON array (e.g. [{\"type\": ...}, ...]).","If actions legitimately arrives as an object, coerce it to a list before calling parse_control_event_payload.","Add a schema check (jsonschema/pydantic) at the event boundary so malformed events fail loudly with a clearer message."],"exampleFix":"// before\n{\"transitions\": [{\"client_ts_ms\": 10, \"actions\": {\"mic\": \"on\"}}]}\n// after\n{\"transitions\": [{\"client_ts_ms\": 10, \"actions\": [\"mic:on\"]}]}","handlingStrategy":"validation","validationCode":"for t in payload.get('transitions', []):\n    if not isinstance(t.get('actions'), list):\n        raise ValueError('transition actions must be a list before parsing')","typeGuard":"def has_valid_transitions(payload: dict) -> bool:\n    return isinstance(payload.get('transitions'), list) and all(\n        isinstance(t, dict) and isinstance(t.get('actions'), list)\n        for t in payload['transitions']\n    )","tryCatchPattern":"try:\n    parse_control_event_payload(raw)\nexcept ValueError as e:\n    drop_or_alert_malformed_event(raw, e)","preventionTips":["Validate control-event payloads against a schema at the producer boundary.","Log rejected payloads with their raw JSON to find which producer emitted the bad shape."],"tags":["control-events","schema-validation","realtime"],"backgroundTag":"payload-schema-validation-failed","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}