sgl-project/sglang · error · TypeError

actions must be a list[list[str]]

Error message

actions must be a list[list[str]]

What it means

The Lingbot World pipeline validates that the per-frame 'actions' argument is a list of lists of strings (one inner list of action names per frame). This TypeError is thrown when the top-level actions value is not a Python list at all — e.g. a string, tuple, numpy array, or None.

Source

Thrown at python/sglang/multimodal_gen/configs/pipeline_configs/lingbot_world.py:68

    def reset_camera_actions(self):
        self.action_history.clear()
        self.last_actions = []

    def append_camera_actions(self, camera_actions: list[list[str]]) -> None:
        for actions in camera_actions:
            normalized = list(actions)
            self.action_history.append(normalized)
            self.last_actions = normalized

    def dispose(self):
        super().dispose()
        self.reset_camera_actions()


def _validate_actions(actions: Any) -> list[list[str]]:
    if not isinstance(actions, list):
        raise TypeError("actions must be a list[list[str]]")
    result: list[list[str]] = []
    for frame_actions in actions:
        if not isinstance(frame_actions, list):
            raise TypeError("actions must be a list[list[str]]")
        result.append(list(frame_actions))
    return result


def _pad_actions_to_chunk(
    action_history: list[list[str]], chunk_size: int
) -> list[list[str]]:
    if len(action_history) >= chunk_size:
        return action_history
    fill_item = action_history[-1] if action_history else []
    return action_history + [
        list(fill_item) for _ in range(chunk_size - len(action_history))
    ]

View on GitHub (pinned to 0132848349)

Solutions

  1. Pass actions as a list of lists of strings: [["move_forward"], ["turn_left", "move_forward"]]
  2. If you have one frame, wrap it: actions=[["move_forward"]] not actions="move_forward"
  3. Convert tuples/arrays to lists before the call: actions=[list(f) for f in actions]
  4. Add a None check / default before calling if actions may be absent

Example fix

# before
actions = "move_forward"  # or ("move_forward",)

# after
actions = [["move_forward"]]
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(actions, list):
    actions = [[str(a)] for a in actions] if actions else []

Type guard

def is_valid_actions(a) -> bool:
    return isinstance(a, list) and all(isinstance(f, list) and all(isinstance(s, str) for s in f) for f in a)

Try / catch

except TypeError as e:
    if "list[list[str]]" in str(e):
        actions = [[a] for a in actions] if isinstance(actions, (list, tuple)) else []
        retry(actions)

Prevention

When it happens

Trigger: Calling generation with actions not being a list, e.g. actions="move_forward" (a plain string), actions=("move","turn") (tuple), actions=None, or a numpy array — _validate_actions fails the outer isinstance(actions, list) check before any frame is inspected.

Common situations: Passing a single action string directly instead of wrapping it; deserializing actions from JSON/YAML into a tuple or array; forgetting the actions argument's nested structure (frames × actions) when porting an example.

Related errors


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