{"record":{"id":"c61cdae42673621e","repo":"roboflow/supervision","slug":"class-id-is-required-for-labelme-export-but-the-p","errorCode":null,"errorMessage":"class_id is required for LabelMe export, but the provided Detections has class_id=None.","messagePattern":"class_id is required for LabelMe export, but the provided Detections has class_id=None\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/dataset/formats/labelme.py","lineNumber":324,"sourceCode":"    Masked detections are exported as ``polygon`` shapes (one per connected\n    component); box-only detections — and masked detections whose mask yields no\n    polygon contour (e.g. an empty or sub-pixel mask) — are exported as\n    ``rectangle`` shapes, so no detection is silently dropped.\n\n    Args:\n        detections: The detections to export.\n        classes: List of class names indexed by ``class_id``.\n\n    Returns:\n        A list of LabelMe shape dicts ready to embed in a ``.json`` annotation.\n\n    Raises:\n        ValueError: If ``detections.class_id`` is ``None`` or if any\n            ``class_id`` value is out of range for ``classes``.\n    \"\"\"\n    class_ids = detections.class_id\n    if class_ids is None:\n        raise ValueError(\n            \"class_id is required for LabelMe export, but the provided \"\n            \"Detections has class_id=None.\"\n        )\n    masks = detections.mask\n    shapes: list[LabelMeDict] = []\n    for index in range(len(detections)):\n        class_index = int(class_ids[index])\n        if class_index < 0 or class_index >= len(classes):\n            raise ValueError(\n                f\"class_id {class_index} at detection index {index} is out of \"\n                f\"range for classes list of length {len(classes)}.\"\n            )\n        label = classes[class_index]\n        if masks is not None:\n            mask_arr = np.asarray(masks[index], dtype=np.bool_)\n            polygons = mask_to_polygons(mask_arr)\n        else:\n            polygons = []","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/dataset/formats/labelme.py#L306-L342","documentation":"Raised by detections_to_labelme_shapes when detections.class_id is None. LabelMe shapes need a text label looked up from the classes list by class index, so detections without class ids cannot be exported. This mirrors the YOLO export requirement but for the LabelMe format.","triggerScenarios":"Calling sv.detections_to_labelme_shapes(detections, classes=[...]) on Detections constructed without class_id (only xyxy/confidence), or after a processing step that dropped class_id.","commonSituations":"Exporting results of a class-agnostic detector (class_id None by design); building Detections from geometric zones or manual boxes for dataset creation; losing class_id through custom filtering code.","solutions":["Provide class ids when constructing the Detections: Detections(xyxy=..., class_id=np.array([0], dtype=int)).","If the detector is class-agnostic, fill class_id with zeros and pass a single-class classes list.","Re-attach class ids from a previous Detections instance before export (e.g. by index or tracker_id)."],"exampleFix":"# before\ndets = sv.Detections(xyxy=xyxy)\nshapes = sv.detections_to_labelme_shapes(dets, classes=['cat'])\n# after\ndets = sv.Detections(xyxy=xyxy, class_id=np.zeros(len(xyxy), dtype=int))\nshapes = sv.detections_to_labelme_shapes(dets, classes=['cat'])","handlingStrategy":"type-guard","validationCode":"import numpy as np\n\ndef ready_for_labelme_export(detections) -> bool:\n    \"\"\"LabelMe export requires a non-None class_id array.\"\"\"\n    return detections.class_id is not None","typeGuard":"def has_class_id(detections) -> bool:\n    \"\"\"True when detections carry a class_id array.\"\"\"\n    return detections.class_id is not None","tryCatchPattern":"try:\n    shapes = sv.detections_to_labelme_shapes(dets, classes=classes)\nexcept ValueError as e:\n    if 'class_id is required for LabelMe' in str(e):\n        dets.class_id = np.zeros(len(dets), dtype=np.int64)\n        shapes = sv.detections_to_labelme_shapes(dets, classes=classes)\n    else:\n        raise","preventionTips":["Pass class ids through every Detections transform in your pipeline.","Use a 0 class id plus single-class names for class-agnostic models.","Unit-test export paths with realistic Detections fixtures."],"tags":["labelme","export","detections","class-id"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}