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

  1. 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).
  2. Extract the decoded text first: pass result['<REGION_TO_CATEGORY>'] or processor.decode(...) output rather than the whole result dict.
  3. If you actually ran a grounding/detection task, use the matching task token ('<OD>', '<OPEN_VOCABULARY_DETECTION>', '<CAPTION_TO_PHRASE_GROUNDING>') instead.
  4. 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

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


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