roboflow/supervision · error · ValueError
Expected string as {task} result, got {type(result)}
Error message
Expected string as {task} result, got {type(result)} What it means
Raised by the Florence-2 post-processing helper in supervision's VLM module when a '<REGION_TO_CATEGORY>' or '<REGION_TO_DESCRIPTION>' task returns something other than a Python string. The parser expects raw text output from the model (e.g. 'a dog<loc_250><loc_100><loc_600><loc_450>') and cannot proceed with a dict or list. This almost always means the Florence-2 model was invoked with the wrong task prompt for the output it produced.
Source
Thrown at src/supervision/detection/vlm.py:588
masks_list.append(mask)
xyxy_box = polygon_to_xyxy(polygon)
xyxy_list.append(xyxy_box)
# per-class labels also provided, but they are ["", "", "", ...]
# when we figure out how to set class names, we can do
# zip(result["labels"], result["polygons"])
xyxy = np.array(xyxy_list, dtype=np.float32)
masks = np.array(masks_list)
return xyxy, None, masks, None
if task == "<OPEN_VOCABULARY_DETECTION>":
xyxy = np.array(result["bboxes"], dtype=np.float32)
labels = np.array(result["bboxes_labels"])
# Also has "polygons" and "polygons_labels", but they don't seem to be used
return xyxy, labels, None, None
if task in ["<REGION_TO_CATEGORY>", "<REGION_TO_DESCRIPTION>"]:
if not isinstance(result, str):
raise ValueError(f"Expected string as {task} result, got {type(result)}")
if result == "No object detected.":
return np.empty((0, 4), dtype=np.float32), np.array([]), None, None
pattern = re.compile(r"<loc_(\d+)><loc_(\d+)><loc_(\d+)><loc_(\d+)>")
match = pattern.search(result)
if match is None:
raise ValueError(
f"Expected string to end in location tags, but got {result}"
)
w, h = _validate_resolution(resolution_wh)
xyxy = np.array([match.groups()], dtype=np.float32)
xyxy *= np.array([w, h, w, h]) / 1000
result_string = result[: match.start()]
labels = np.array([result_string])
return xyxy, labels, None, None
View on GitHub (pinned to 7f254d9784)
Solutions
- Make sure the task passed to from_florence_2 is exactly the task prompt sent to the model (e.g. '<REGION_TO_CATEGORY>' both at inference and at parsing).
- Extract the decoded text first: pass result['<REGION_TO_CATEGORY>'] or processor.decode(...) output rather than the whole result dict.
- If you actually ran a grounding/detection task, use the matching task token ('<OD>', '<OPEN_VOCABULARY_DETECTION>', '<CAPTION_TO_PHRASE_GROUNDING>') instead.
- Add an isinstance(result, str) check before calling and log type(result) to identify the mismatch.
Example fix
# before
detections = sv.Detections.from_florence_2(
result=parsed_answer, task="<REGION_TO_CATEGORY>"
)
# after
detections = sv.Detections.from_florence_2(
result=parsed_answer["<REGION_TO_CATEGORY>"],
task="<REGION_TO_CATEGORY>",
) Defensive patterns
Strategy: type-guard
Validate before calling
from typing import Any
raw = parsed_answer["<REGION_TO_CATEGORY>"] if isinstance(parsed_answer, dict) else parsed_answer
if not isinstance(raw, str):
raise TypeError(f"Expected decoded string, got {type(raw)}") Type guard
def is_florence2_text_result(result: Any) -> bool:
return isinstance(result, str) Try / catch
try:
detections = sv.Detections.from_florence_2(result=raw, task="<REGION_TO_CATEGORY>")
except ValueError as e:
logger.warning("Skipping frame: Florence-2 result/task mismatch: %s", e)
detections = sv.Detections.empty() Prevention
- Keep the task token in a single variable used for both inference and parsing.
- Extract the per-task entry from the Florence-2 result dict before calling from_florence_2.
- Log type(result) once when integrating a new checkpoint.
When it happens
Trigger: Calling sv.Detections.from_florence_2(result, task='<REGION_TO_CATEGORY>') or '<REGION_TO_DESCRIPTION>' where result is a dict/list (e.g. the model actually ran '<OD>' or '<OPEN_VOCABULARY_DETECTION>', which return dicts) or a batched/decoded object that is not a plain str.
Common situations: Copying a task string from one Florence-2 example but a result object from another; post-processing outputs from a different task than the one used for inference; upgrading transformers so the processor returns ProcessedOutput objects instead of strings.
Related errors
- Invalid VLM result type: {type(result)}. Must be dict.
- Expected string to end in location tags, but got {result}
- Invalid vlm value: {vlm}. Must be one of {[e.value for e in
- module {__name__} has no attribute {name}
- Edge indices must use the 1-based convention and be within t
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/b1d7c0326b5e0a85.
Report an issue: GitHub.