roboflow/supervision · error · ValueError

Invalid VLM result type: {type(result)}. Must be str.

Error message

Invalid VLM result type: {type(result)}. Must be str.

What it means

Inside Detections.from_vlm, the PaliGemma branch parses raw model output text (the <det> token sequence in the PaliGemma prompt format). The parser from_paligemma only accepts str, so any other result type (dict, list, bytes, parsed JSON) raises this ValueError before parsing.

Source

Thrown at src/supervision/detection/core.py:2029

            >>> detections.xyxy
            array([[ 580.58057 ,  270.27026 , 1000.      ,  904.9049  ],
                   [  26.026026,   31.03103 ,  632.6326  ,  998.999   ]],
                  dtype=float32)
            >>> detections.class_id
            array([0, 1])
            >>> detections.data
            {'class_name': array(['The giraffe at the back', 'The giraffe at the front'],
                  dtype='<U24')}

            ```

        """  # noqa: E501

        vlm = _validate_vlm_parameters(vlm, result, kwargs)

        if vlm == VLM.PALIGEMMA:
            if not isinstance(result, str):
                raise ValueError(
                    f"Invalid VLM result type: {type(result)}. Must be str."
                )
            xyxy, class_id, class_name = from_paligemma(result, **kwargs)
            data: _DetectionDataType = {
                CLASS_NAME_DATA_FIELD: class_name,
            }
            return cls(xyxy=xyxy, class_id=class_id, data=data)

        if vlm == VLM.QWEN_2_5_VL:
            if not isinstance(result, str):
                raise ValueError(
                    f"Invalid VLM result type: {type(result)}. Must be str."
                )
            xyxy, class_id, class_name = from_qwen_2_5_vl(result, **kwargs)
            data = {CLASS_NAME_DATA_FIELD: class_name}
            confidence_arr: npt.NDArray[np.floating[Any]] = np.ones(
                len(xyxy), dtype=float
            )

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Decode the model output to its raw string with special tokens intact: processor.decode(outputs[0], skip_special_tokens=False) — PaliGemma detection tokens (<det>...) must not be stripped.
  2. If the result came from an API wrapper, extract the text field before passing.
  3. Keep skip_special_tokens=False; PaliGemma box tokens are special tokens and are required by the parser.

Example fix

# before
outputs = model.generate(**inputs)
detections = sv.Detections.from_vlm(vlm=sv.VLM.PALIGEMMA, result=outputs)  # tensor

# after
import supervision as sv
text = processor.decode(outputs[0], skip_special_tokens=False)
detections = sv.Detections.from_vlm(vlm=sv.VLM.PALIGEMMA, result=text)
Defensive patterns

Strategy: type-guard

Validate before calling

text = (
    result if isinstance(result, str)
    else processor.decode(result[0], skip_special_tokens=False)
)
assert isinstance(text, str)
detections = sv.Detections.from_vlm(vlm=sv.VLM.PALIGEMMA, result=text)

Type guard

def paligemma_result_str(result) -> bool:
    return isinstance(result, str)

Try / catch

try:
    detections = sv.Detections.from_vlm(vlm=sv.VLM.PALIGEMMA, result=result)
except ValueError as e:
    if 'Must be str' in str(e):
        result = processor.decode(result[0], skip_special_tokens=False)
        detections = sv.Detections.from_vlm(vlm=sv.VLM.PALIGEMMA, result=result)
    else:
        raise

Prevention

When it happens

Trigger: Calling from_vlm(vlm=sv.VLM.PALIGEMMA, result=...) (or from_lmm with lmm='paligemma') where result is a dict, list of tokens, or an object with a .text attribute instead of the decoded string.

Common situations: Passing the transformers generate() tensor output instead of processor.decode(..., skip_special_tokens=False) text; passing a Roboflow/Hosted API response object or dict; pre-parsing the output with json.loads.

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/14612510178e9201. Report an issue: GitHub.