{"record":{"id":"2d2b8f73a16f3274","repo":"sgl-project/sglang","slug":"camera-actions-event-payload-must-be-list-list-str","errorCode":null,"errorMessage":"camera_actions event payload must be list[list[str]]","messagePattern":"camera_actions event payload must be list\\[list\\[str\\]\\]","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/entrypoints/openai/realtime/adapters/lingbot_world_realtime_adapter.py","lineNumber":138,"sourceCode":"    async def on_init(\n        self,\n        session: GenerateSession,\n        request: RealtimeVideoGenerationsRequest,\n    ) -> None:\n        condition_inputs = request.condition_inputs or {}\n        camera_actions = condition_inputs.get(LINGBOT_CAMERA_ACTIONS_CONDITION)\n        if camera_actions is not None:\n            state = self._state(session)\n            state.receive_camera_action_script(\n                self._validate_camera_actions(camera_actions)\n            )\n\n        await save_realtime_first_frame(session, request)\n\n    @staticmethod\n    def _validate_camera_actions(payload: Any) -> list[list[str]]:\n        if not isinstance(payload, list):\n            raise ValueError(\"camera_actions event payload must be list[list[str]]\")\n        normalized = []\n        for frame_actions in payload:\n            if not isinstance(frame_actions, list):\n                raise ValueError(\"camera_actions event payload must be list[list[str]]\")\n            normalized.append(list(frame_actions))\n        return normalized\n\n    def ingest_event(\n        self,\n        session: GenerateSession,\n        event: RealtimeEvent,\n    ) -> str:\n        state = self._state(session)\n        if event.kind == \"camera_actions\":\n            return self._ingest_camera_actions(state, event.payload, event.event_id)\n        elif event.kind == \"prompt\":\n            return self._ingest_prompt(state, event.payload, event.event_id)\n        elif event.kind == COMPOSITE_INPUT_EVENT_KIND:","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/entrypoints/openai/realtime/adapters/lingbot_world_realtime_adapter.py#L120-L156","documentation":"_validate_camera_actions rejects a camera_actions payload whose top level is not a list. The API expects list[list[str]] — one list of action strings per frame.","triggerScenarios":"on_init receiving condition_inputs.camera_actions as a dict/string, or ingest_event with a camera_actions payload that is not a JSON array.","commonSituations":"Sending camera actions as an object keyed by frame ({\"0\": [...]}) or a flat string script instead of nested arrays; schema drift between client and adapter.","solutions":["Send camera_actions as an array of arrays of strings, e.g. [[\"turn_left\"],[\"zoom_in\"]]","If you have a single script string, use the 'action' condition input instead","Validate the payload shape client-side before sending"],"exampleFix":"// before\n{\"camera_actions\": \"turn_left,zoom_in\"}\n// after\n{\"camera_actions\": [[\"turn_left\"],[\"zoom_in\"]]}","handlingStrategy":"type-guard","validationCode":"assert isinstance(payload, list), 'camera_actions must be a list of frames'","typeGuard":"def is_camera_actions(x: object) -> bool:\n    return isinstance(x, list) and all(isinstance(f, list) and all(isinstance(a, str) for a in f) for f in x)","tryCatchPattern":null,"preventionTips":["Nest one array per frame","Use 'action' string for single-script control"],"tags":["realtime","event-validation","camera-actions","type-mismatch"],"backgroundTag":"event-payload-type-mismatch","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}