sgl-project/sglang · error · ValueError

action must have shape [T, D], got {tuple(action.shape)}

Error message

action must have shape [T, D], got {tuple(action.shape)}

What it means

After converting the provided action array to a tensor (and squeezing a leading batch dim of 1), the stage requires ndim==2, i.e. shape [timesteps, action_dim]. Flat vectors, per-frame nested batches, or scalars fail this check.

Source

Thrown at python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/cosmos3.py:707

        if raw_action_dim is None:
            embodiment = getattr(sp, "domain_name", None)
            if embodiment:
                raw_action_dim = get_raw_action_dim(embodiment)

        if mode == ACTION_MODE_FORWARD_DYNAMICS:
            raw = getattr(sp, "action", None)
            if raw is None:
                raise ValueError(
                    "action_mode='forward_dynamics' requires an 'action' array "
                    "(list[list[float]] of shape [T, D])."
                )
            if isinstance(raw, str):
                raw = json.loads(raw)
            action = torch.as_tensor(np.asarray(raw), dtype=torch.float32)
            if action.ndim == 3 and action.shape[0] == 1:
                action = action.squeeze(0)
            if action.ndim != 2:
                raise ValueError(
                    f"action must have shape [T, D], got {tuple(action.shape)}"
                )
            if action.shape[0] < action_chunk_size:
                pad = action[-1:].repeat(action_chunk_size - action.shape[0], 1)
                action = torch.cat([action, pad], dim=0)
            elif action.shape[0] > action_chunk_size:
                action = action[:action_chunk_size]
            if raw_action_dim is None:
                raw_action_dim = int(action.shape[-1])
            stats_path = getattr(sp, "action_stats_path", None)
            if stats_path is not None:
                method = getattr(sp, "action_normalization", "quantile")
                action = normalize_action(action, method, load_action_stats(stats_path))
            if action.shape[-1] < action_dim:
                pad = torch.zeros(action.shape[0], action_dim - action.shape[-1])
                action = torch.cat([action, pad], dim=-1)
            clean_action = action.to(device=device, dtype=dtype).unsqueeze(0)
        else:

View on GitHub (pinned to 0132848349)

Solutions

  1. Reshape the action data to [T, D]: wrap a single step as [[...]]
  2. If sending a batched tensor, keep batch dim = 1 or split per-request
  3. Validate action array shape client-side before submitting the request

Example fix

# before
sp.action = [0.0, 1.0, 0.0]

# after
sp.action = [[0.0, 1.0, 0.0]]  # shape [1, 3]
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np
a = np.asarray(sp.action, dtype='float32')
if a.ndim == 3 and a.shape[0] == 1: a = a[0]
assert a.ndim == 2, f'action must be [T, D], got {a.shape}'

Type guard

def action_is_2d(action) -> bool:
    import numpy as np
    a = np.asarray(action)
    if a.ndim == 3 and a.shape[0] == 1:
        a = a[0]
    return a.ndim == 2

Prevention

When it happens

Trigger: Passing sp.action as a flat list of D floats ([D]), a scalar, or a 3D array with batch dim != 1; each yields ndim != 2 after the squeeze.

Common situations: Supplying a single action step as a flat vector instead of [[...]], or sending multiple rollouts stacked along dim 0.

Related errors


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