{"record":{"id":"1c113b374f068a53","repo":"sgl-project/sglang","slug":"error-label-must-be-list-list-str","errorCode":null,"errorMessage":"{error_label} must be list[list[str]]","messagePattern":"(.+?) must be list\\[list\\[str\\]\\]","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/sana_wm/base.py","lineNumber":111,"sourceCode":") -> tuple[int, int, int, int]:\n    scale = max(target_h / float(src_h), target_w / float(src_w))\n    resized_w = max(target_w, int(round(src_w * scale)))\n    resized_h = max(target_h, int(round(src_h * scale)))\n    left = (resized_w - target_w) // 2\n    top = (resized_h - target_h) // 2\n    return resized_w, resized_h, left, top\n\n\ndef normalize_sana_wm_camera_actions(\n    payload: Any,\n    *,\n    allow_none: bool = False,\n    error_label: str = \"camera_actions\",\n) -> list[list[str]]:\n    if payload is None and allow_none:\n        return []\n    if not isinstance(payload, list):\n        raise ValueError(f\"{error_label} must be list[list[str]]\")\n    out: list[list[str]] = []\n    for frame_actions in payload:\n        if not isinstance(frame_actions, list):\n            raise ValueError(f\"{error_label} must be list[list[str]]\")\n        out.append([str(key).lower() for key in frame_actions])\n    return out\n\n\ndef parse_sana_wm_action_string(action: str) -> list[list[str]]:\n    cleaned = \"\".join(action.replace(\"，\", \",\").split())\n    if not cleaned:\n        raise ValueError(\"action string is empty\")\n\n    per_frame: list[list[str]] = []\n    for segment in cleaned.split(\",\"):\n        if not segment or \"-\" not in segment:\n            raise ValueError(\n                f\"invalid action segment {segment!r}; expected '<keys>-<frames>'\"","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/sana_wm/base.py#L93-L129","documentation":"Raised by normalize_sana_wm_camera_actions when the payload for camera_actions is not a list (outer level). The function normalizes camera action data into list[list[str]] (lowercased keys per frame); any non-list top-level input fails immediately.","triggerScenarios":"Calling normalize_sana_wm_camera_actions (directly or via _validate_camera_actions / _normalize_camera_actions) with a string, dict, tuple, or None (when allow_none=False) instead of a list of frame action lists.","commonSituations":"Passing a raw action string like 'ab-4' where a structured list is expected, or passing None without allow_none=True, or a tuple instead of a list after JSON round-tripping.","solutions":["Pass camera actions as a list of lists of strings, e.g. [['a','b'], ['a']]","If None is legitimate, call with allow_none=True","Wrap strings in a single-frame list: [[key] for key in keys]"],"exampleFix":"// before\nnormalize_sana_wm_camera_actions('ab')\n// after\nnormalize_sana_wm_camera_actions([['a','b']])","handlingStrategy":"validation","validationCode":"assert isinstance(actions, list) and all(isinstance(f, list) for f in actions), 'camera_actions must be list[list[str]]'","typeGuard":"def is_camera_actions(v) -> bool:\n    return isinstance(v, list) and all(isinstance(f, list) and all(isinstance(k, str) for k in f) for f in v)","tryCatchPattern":null,"preventionTips":["Validate config shape at request ingestion, not deep in the pipeline","Use allow_none=True when None is a valid 'no actions' state"],"tags":["validation","camera-actions","sana-wm"],"backgroundTag":"schema-validation-failed","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}