sgl-project/sglang · error · ValueError
{error_label} must be list[list[str]]
Error message
{error_label} must be list[list[str]] What it means
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.
Source
Thrown at python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/sana_wm/base.py:111
) -> tuple[int, int, int, int]:
scale = max(target_h / float(src_h), target_w / float(src_w))
resized_w = max(target_w, int(round(src_w * scale)))
resized_h = max(target_h, int(round(src_h * scale)))
left = (resized_w - target_w) // 2
top = (resized_h - target_h) // 2
return resized_w, resized_h, left, top
def normalize_sana_wm_camera_actions(
payload: Any,
*,
allow_none: bool = False,
error_label: str = "camera_actions",
) -> list[list[str]]:
if payload is None and allow_none:
return []
if not isinstance(payload, list):
raise ValueError(f"{error_label} must be list[list[str]]")
out: list[list[str]] = []
for frame_actions in payload:
if not isinstance(frame_actions, list):
raise ValueError(f"{error_label} must be list[list[str]]")
out.append([str(key).lower() for key in frame_actions])
return out
def parse_sana_wm_action_string(action: str) -> list[list[str]]:
cleaned = "".join(action.replace(",", ",").split())
if not cleaned:
raise ValueError("action string is empty")
per_frame: list[list[str]] = []
for segment in cleaned.split(","):
if not segment or "-" not in segment:
raise ValueError(
f"invalid action segment {segment!r}; expected '<keys>-<frames>'"View on GitHub (pinned to 0132848349)
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]
Example fix
// before
normalize_sana_wm_camera_actions('ab')
// after
normalize_sana_wm_camera_actions([['a','b']]) Defensive patterns
Strategy: validation
Validate before calling
assert isinstance(actions, list) and all(isinstance(f, list) for f in actions), 'camera_actions must be list[list[str]]'
Type guard
def is_camera_actions(v) -> bool:
return isinstance(v, list) and all(isinstance(f, list) and all(isinstance(k, str) for k in f) for f in v) Prevention
- Validate config shape at request ingestion, not deep in the pipeline
- Use allow_none=True when None is a valid 'no actions' state
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- plucker_emb token count {plucker_emb.shape[1]} != latent tok
- chunk_size must be > 0, got {chunk_size}.
- action string is empty
- invalid action segment {segment!r}; expected '<keys>-<frames
- invalid duration in action segment {segment!r}
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/1c113b374f068a53.
Report an issue: GitHub.