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

  1. Pass camera actions as a list of lists of strings, e.g. [['a','b'], ['a']]
  2. If None is legitimate, call with allow_none=True
  3. 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

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


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/1c113b374f068a53. Report an issue: GitHub.