{"record":{"id":"3e5ee8a3a0df280d","repo":"sgl-project/sglang","slug":"pi05-noise-must-have-shape-expected-got-tuple","errorCode":null,"errorMessage":"Pi05 noise must have shape {expected}, got {tuple(noise_tensor.shape)}","messagePattern":"Pi05 noise must have shape (.+?), got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/pi05_preprocess.py","lineNumber":200,"sourceCode":"            if state_tensor.ndim == 1:\n                state_tensor = state_tensor.unsqueeze(0)\n            if state_tensor.shape[0] != 1:\n                raise ValueError(\"Pi05 v1 expects one state vector per request\")\n            if state_tensor.shape[-1] > self.config.state_dim:\n                raise ValueError(\n                    f\"Pi05 state dim must be <= {self.config.state_dim}, \"\n                    f\"got {state_tensor.shape[-1]}\"\n                )\n\n        noise = raw_observation.get(\"noise\")\n        noise_tensor = None\n        if noise is not None:\n            noise_tensor = torch.as_tensor(noise, dtype=torch.float32)\n            if noise_tensor.ndim == 2:\n                noise_tensor = noise_tensor.unsqueeze(0)\n            expected = (1, self.config.action_horizon, self.config.action_dim)\n            if tuple(noise_tensor.shape) != expected:\n                raise ValueError(\n                    f\"Pi05 noise must have shape {expected}, \"\n                    f\"got {tuple(noise_tensor.shape)}\"\n                )\n\n        tokens = raw_observation.get(\"tokens\")\n        if tokens is None:\n            tokens = raw_observation.get(\"tokenized_prompt\")\n        token_masks = raw_observation.get(\"token_masks\")\n        if token_masks is None:\n            token_masks = raw_observation.get(\"tokenized_prompt_mask\")\n        if tokens is not None:\n            tokens_tensor = torch.as_tensor(tokens, dtype=torch.long)\n            if tokens_tensor.ndim == 1:\n                tokens_tensor = tokens_tensor.unsqueeze(0)\n            if token_masks is None:\n                token_masks_tensor = tokens_tensor != self.tokenizer.pad_token_id\n            else:\n                token_masks_tensor = torch.as_tensor(token_masks, dtype=torch.bool)","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/pi05_preprocess.py#L182-L218","documentation":"When explicit flow-matching noise is supplied to the Pi05 stage, it must match the expected action-noise layout of exactly [1, action_horizon, action_dim] (a 2-D [H, D] input is auto-unsqueezed to [1, H, D]). Any other shape is rejected because the denoiser expects noise aligned token-for-token with the action trajectory.","triggerScenarios":"Passing raw_observation['noise'] with shape [1, D] (missing horizon axis), [B, H, D] with B>1, [H, D, W], or any tensor whose dims don't equal (1, config.action_horizon, config.action_dim).","commonSituations":"Sampling noise with the wrong horizon/dim from a config mismatch (action_dim or action_horizon changed between training and serving); reusing cached noise tensors after changing chunk length; batched generation attempts.","solutions":["Generate noise as torch.randn(1, cfg.action_horizon, cfg.action_dim) (or let the stage sample it by omitting 'noise').","Verify config.action_horizon / config.action_dim match the checkpoint you serve.","If you have [H, D], it is auto-unsqueezed — but never pass batched noise."],"exampleFix":"# before\nobs = {\"noise\": torch.randn(1, cfg.action_dim), ...}\n\n# after\nobs = {\"noise\": torch.randn(1, cfg.action_horizon, cfg.action_dim), ...}","handlingStrategy":"validation","validationCode":"if noise is not None:\n    n = torch.as_tensor(noise, dtype=torch.float32)\n    if n.ndim == 2: n = n.unsqueeze(0)\n    assert tuple(n.shape) == (1, cfg.action_horizon, cfg.action_dim)","typeGuard":"def noise_shape_ok(noise, cfg) -> bool:\n    if noise is None: return True\n    n = torch.as_tensor(noise)\n    if n.ndim == 2: n = n.unsqueeze(0)\n    return tuple(n.shape) == (1, cfg.action_horizon, cfg.action_dim)","tryCatchPattern":null,"preventionTips":["Usually omit 'noise' and let the stage sample it.","Regenerate cached noise whenever action_horizon/action_dim config changes."],"tags":["pi05","vla","noise","shape-validation","flow-matching","torch"],"backgroundTag":"tensor-shape-mismatch","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}