sgl-project/sglang · error · ValueError

Pi05 v1 expects one prompt per action request

Error message

Pi05 v1 expects one prompt per action request

What it means

The Pi05 v1 preprocessing stage requires exactly one text prompt per action request. The stage reads raw_observation['prompt'], stringifies it (or each element if it's a list), and rejects anything that does not reduce to a single prompt, because the downstream model invocation is built for batch size 1.

Source

Thrown at python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/pi05_preprocess.py:155

        encoded = self.tokenizer(
            full_prompts,
            max_length=self.config.max_token_len,
            padding="max_length",
            truncation=True,
            return_tensors="pt",
        )
        return encoded["input_ids"].to(torch.long), encoded["attention_mask"].to(
            torch.bool
        )

    def __call__(self, raw_observation: dict[str, Any]) -> VLAObservationBatch:
        prompt_value = raw_observation.get("prompt", "")
        if isinstance(prompt_value, list):
            prompt = [str(x) for x in prompt_value]
        else:
            prompt = [str(prompt_value)]
        if len(prompt) != 1:
            raise ValueError("Pi05 v1 expects one prompt per action request")

        raw_images = raw_observation.get("images") or {}
        image_masks_in = raw_observation.get("image_masks") or {}
        camera_order = tuple(
            raw_observation.get("camera_order") or self.config.image_keys
        )

        images: dict[str, torch.Tensor] = {}
        image_masks: dict[str, torch.Tensor] = {}
        for key in camera_order:
            value = raw_images.get(key)
            is_present = value is not None and bool(image_masks_in.get(key, True))
            if is_present:
                tensor = _preprocess_image(value, self.config.image_size)
            else:
                channels = 3
                height, width = self.config.image_size
                tensor = torch.ones(channels, height, width, dtype=torch.float32) * -1.0

View on GitHub (pinned to 0132848349)

Solutions

  1. Set raw_observation['prompt'] to a single string (or a one-element list) per request.
  2. If you need multiple prompts, split them into separate action requests and call the stage once each.
  3. Add a pre-check in your data loader that asserts len(prompt)==1 before dispatching.

Example fix

# before
raw_observation = {"prompt": ["pick up the cup", "stack the block"]}
stage(raw_observation)

# after
for p in ["pick up the cup", "stack the block"]:
    stage({"prompt": p})
Defensive patterns

Strategy: validation

Validate before calling

p = raw_observation.get("prompt", "")
plist = p if isinstance(p, list) else [p]
assert len(plist) == 1, f"expected 1 prompt, got {len(plist)}"

Type guard

from typing import Union

def is_single_prompt(obs: dict) -> bool:
    p = obs.get("prompt", "")
    return not isinstance(p, list) or len(p) == 1

Try / catch

try:
    out = stage(raw_observation)
except ValueError as e:
    if "one prompt per action request" in str(e):
        # split and retry per-prompt
        ...
    raise

Prevention

When it happens

Trigger: Calling the pi05 preprocess stage with raw_observation['prompt'] being a list of length != 1, e.g. ['a','b'], or a value that stringifies to something combined with a list of 2+ items. Any multi-prompt batched request triggers it.

Common situations: Porting batched VLA inference code from another framework that supports multiple prompts per request; accidentally wrapping the prompt in extra list nesting; feeding a list of prompts when iterating a dataset without splitting per-sample.

Related errors


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