{"record":{"id":"e3edcb26558159b0","repo":"sgl-project/sglang","slug":"action-output-must-have-shape-h-d-or-b-h-d","errorCode":null,"errorMessage":"action output must have shape [H, D] or [B, H, D], got {tuple(action_array.shape)}","messagePattern":"action output must have shape \\[H, D\\] or \\[B, H, D\\], got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":500,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/entrypoints/action/protocol.py","lineNumber":444,"sourceCode":"\n\ndef action_generation_response(\n    output: dict[str, Any],\n    server_args: ServerArgs,\n    *,\n    preserve_numpy: bool = False,\n) -> dict[str, Any]:\n    actions = output[\"actions\"]\n    action_array = np.asarray(actions)\n    if any(size == 0 for size in action_array.shape):\n        raise ValueError(\n            \"action output dimensions must be non-zero, got \"\n            f\"{tuple(action_array.shape)}\"\n        )\n    if action_array.ndim == 2:\n        action_array = action_array[None]\n    elif action_array.ndim != 3:\n        raise ValueError(\n            \"action output must have shape [H, D] or [B, H, D], got \"\n            f\"{tuple(action_array.shape)}\"\n        )\n\n    data = []\n    for input_index, action_values in enumerate(action_array):\n        action_shape = list(action_values.shape)\n        if not preserve_numpy:\n            action_values = action_values.tolist()\n        action = {\n            \"type\": \"continuous\",\n            \"dtype\": \"float32\",\n            \"shape\": action_shape,\n            \"values\": action_values,\n        }\n        for name in (\"action_mode\", \"domain_id\", \"raw_action_dim\"):\n            if output.get(name) is not None:\n                action[name] = output[name]","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/entrypoints/action/protocol.py#L426-L462","documentation":"Raised by action_generation_response when the action array, after zero-dimension checks, is neither 2-D (expected [H, D], auto-promoted to [1, H, D]) nor 3-D ([B, H, D]). Any other rank (0-D, 1-D, 4-D+) is rejected because the response format only supports single or batched action sequences with horizon and action-dim axes.","triggerScenarios":"Calling action_generation_response (directly or via create_action_generation / action_realtime_ws) with output['actions'] shaped like a flat vector (D,), a scalar, or a 4-D array.","commonSituations":"Policy head emits a flat action vector per step instead of a sequence, wrong tensor reshaping upstream, tests feeding raw 1-D action vectors.","solutions":["Reshape the policy output to [H, D] (horizon, action_dim) or [B, H, D] before passing it in","Check the action head's output reshaping code upstream for a missing horizon/batch axis","If only a single action step is produced, expand dims: arr[None, :] to make it [1, D] -> [1, 1, D]"],"exampleFix":"# before\noutput = {\"actions\": np.zeros(8)}  # shape (8,) -> ValueError\n\n# after\noutput = {\"actions\": np.zeros((1, 8))}  # [H=1, D=8] -> auto [1,1,8]","handlingStrategy":"type-guard","validationCode":"import numpy as np\narr = np.asarray(output[\"actions\"])\nassert arr.ndim in (2, 3), f\"bad action rank {arr.ndim}\"","typeGuard":"def is_valid_action_shape(actions) -> bool:\n    a = np.asarray(actions)\n    return a.ndim in (2, 3) and all(s > 0 for s in a.shape)","tryCatchPattern":null,"preventionTips":["Normalize policy output to [B, H, D] immediately after inference (arr[None] if 2-D)","Unit-test the reshaping code in the action head","Reject 1-D/4-D arrays early with a clear message"],"tags":["action-inference","shape-validation","numpy"],"backgroundTag":"tensor-shape-validation","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}