roboflow/supervision · error · ValueError
Invalid VLM result type: {type(result)}. Must be dict.
Error message
Invalid VLM result type: {type(result)}. Must be dict. What it means
The FLORENCE_2 branch of Detections.from_vlm expects the Florence-2 post-processed output as a dict — typically {'<TASK>': value} entries produced by the Florence2Processor, e.g. {'<OD>': 'box1...</od>'} or '<OD>' plus '<OD_SEGMENTS>'. The parser from_florence_2 requires a dict; strings raise this ValueError.
Source
Thrown at src/supervision/detection/core.py:2075
xyxy, class_id, class_name = from_qwen_3_vl(result, **kwargs)
data = {CLASS_NAME_DATA_FIELD: class_name}
confidence_arr = np.ones(len(xyxy), dtype=float)
return cls(
xyxy=xyxy, class_id=class_id, confidence=confidence_arr, data=data
)
if vlm == VLM.DEEPSEEK_VL_2:
if not isinstance(result, str):
raise ValueError(
f"Invalid VLM result type: {type(result)}. Must be str."
)
xyxy, class_id, class_name = from_deepseek_vl_2(result, **kwargs)
data = {CLASS_NAME_DATA_FIELD: class_name}
return cls(xyxy=xyxy, class_id=class_id, data=data)
if vlm == VLM.FLORENCE_2:
if not isinstance(result, dict):
raise ValueError(
f"Invalid VLM result type: {type(result)}. Must be dict."
)
xyxy, labels, mask, xyxyxyxy = from_florence_2(result, **kwargs)
if len(xyxy) == 0:
empty = cls.empty()
empty.data = {CLASS_NAME_DATA_FIELD: np.empty(0, dtype=str)}
return empty
data = {}
if labels is not None:
data[CLASS_NAME_DATA_FIELD] = labels
if xyxyxyxy is not None:
data[ORIENTED_BOX_COORDINATES] = xyxyxyxy
return cls(xyxy=xyxy, mask=mask, data=data)
if vlm == VLM.GOOGLE_GEMINI_2_0:
if not isinstance(result, str):View on GitHub (pinned to 7f254d9784)
Solutions
- Run outputs through Florence2Processor.post_process_generation(generated_ids, task='<OD>', image_size=(h, w)) and pass the resulting dict.
- Keep the whole dict — the parser reads the task keys itself; do not pre-extract strings.
- For segmentation use task '<OD_SEGMENTS>'/'<REFERRING_EXPRESSION_SEGMENTATION>' so the dict contains segmentation entries.
Example fix
# before
text = processor.decode(generated_ids[0], skip_special_tokens=False)
detections = sv.Detections.from_vlm(vlm=sv.VLM.FLORENCE_2, result=text) # str -> ValueError
# after
parsed = processor.post_process_generation(
text, task='<OD>', image_size=(image.height, image.width)
)
detections = sv.Detections.from_vlm(vlm=sv.VLM.FLORENCE_2, result=parsed) Defensive patterns
Strategy: type-guard
Validate before calling
parsed = (
result if isinstance(result, dict)
else processor.post_process_generation(result, task='<OD>', image_size=(h, w))
)
assert isinstance(parsed, dict)
detections = sv.Detections.from_vlm(vlm=sv.VLM.FLORENCE_2, result=parsed) Type guard
def is_florence2_result_dict(result) -> bool:
return isinstance(result, dict) Try / catch
try:
detections = sv.Detections.from_vlm(vlm=sv.VLM.FLORENCE_2, result=result)
except ValueError as e:
if 'Must be dict' in str(e):
parsed = processor.post_process_generation(result, task='<OD>', image_size=(h, w))
detections = sv.Detections.from_vlm(vlm=sv.VLM.FLORENCE_2, result=parsed)
else:
raise Prevention
- Always run post_process_generation for Florence-2
- Pass the full task dict, not extracted strings
- Match the task token to the capability you want (OD vs segmentation)
When it happens
Trigger: Calling from_vlm(vlm=sv.VLM.FLORENCE_2, result='box_1 ... ...') with a raw string; passing the decoded generation text instead of processor.post_process_generation(...) output; passing a list of task results.
Common situations: Skipping post_process_generation and decoding generate() output manually; extracting one task's string value from the dict and passing that; using a wrapper that flattens dict output to text.
Related errors
- Invalid VLM result type: {type(result)}. Must be str.
- Invalid type for 'lmm': {type(lmm)}. Must be LMM or str.
- Expected string as {task} result, got {type(result)}
- Expected string to end in location tags, but got {result}
- Unsupported VLM value: {vlm}.
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/3aa76cb72a3e558f.
Report an issue: GitHub.