{"record":{"id":"448365560ca1a281","repo":"roboflow/supervision","slug":"createml-annotation-file-contains-duplicate-entrie","errorCode":null,"errorMessage":"CreateML annotation file contains duplicate entries for image {image_name}. Each image must appear at most once.","messagePattern":"CreateML annotation file contains duplicate entries for image (.+?)\\. Each image must appear at most once\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/dataset/formats/createml.py","lineNumber":211,"sourceCode":"\n    image_paths: list[str] = []\n    annotations: dict[str, Detections] = {}\n    for entry in tqdm(\n        createml_data,\n        desc=\"Loading CreateML annotations\",\n        disable=not show_progress,\n    ):\n        image_name = entry.get(\"image\")\n        if image_name is None:\n            raise ValueError(\n                f\"CreateML annotation entry is missing the required 'image' key: \"\n                f\"{entry!r}\"\n            )\n        image_path = _resolve_image_path(\n            images_directory_path=images_directory_path, image_name=image_name\n        )\n        if image_path in annotations:\n            raise ValueError(\n                f\"CreateML annotation file contains duplicate entries for image \"\n                f\"{image_name!r}. Each image must appear at most once.\"\n            )\n        annotations[image_path] = createml_annotations_to_detections(\n            image_annotations=entry.get(\"annotations\") or [],\n            class_to_index=class_to_index,\n        )\n        image_paths.append(image_path)\n\n    return classes, image_paths, annotations\n\n\ndef detections_to_createml_annotations(\n    detections: Detections, classes: list[str]\n) -> list[CreateMLDict]:\n    \"\"\"Convert ``Detections`` into a list of CreateML annotation dicts.\n\n    Each bounding box is stored as a pixel-space centre point plus width and","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/dataset/formats/createml.py#L193-L229","documentation":"Raised by load_createml_annotations when two entries resolve to the same canonical image path (dict lookup on the resolved path). Each image may appear at most once; a duplicate would silently overwrite the earlier entry's Detections.","triggerScenarios":"Two entries with the same \"image\" value, or aliasing values (\"a.jpg\" vs \"./a.jpg\") that collapse after resolution — the resolver deliberately canonicalizes so aliases do not sneak past this check.","commonSituations":"Concatenating per-batch CreateML files without deduplication; copy-pasted entries; case-insensitive filesystems where differently-cased names collide.","solutions":["Deduplicate entries on the resolved image path, merging their annotations arrays if both are valid.","Check for duplicates before loading: paths = [Path(imgs_dir, e['image']).resolve() for e in data]; assert len(set(paths)) == len(paths).","If two distinct images share a basename, put them in subfolders and use distinct relative paths."],"exampleFix":"// before\n[{\"image\": \"a.jpg\", \"annotations\": [...]}, {\"image\": \"./a.jpg\", \"annotations\": [...]}]\n\n// after\n[{\"image\": \"a.jpg\", \"annotations\": [...merged...]}]","handlingStrategy":"validation","validationCode":"import json\nfrom pathlib import Path\n\ndef assert_unique_createml_images(annotations_path: str, images_dir: str) -> None:\n    \"\"\"Fail fast if two entries resolve to the same image path.\"\"\"\n    entries = json.loads(Path(annotations_path).read_text())\n    seen: set[str] = set()\n    for e in entries:\n        p = str(Path(images_dir, e[\"image\"]).resolve())\n        if p in seen:\n            raise ValueError(f\"Duplicate image {e['image']!r}\")\n        seen.add(p)","typeGuard":"def createml_images_are_unique(entries: list[dict], images_dir: str) -> bool:\n    \"\"\"True when all resolved image paths are distinct.\"\"\"\n    paths = [str(Path(images_dir, e[\"image\"]).resolve()) for e in entries]\n    return len(set(paths)) == len(paths)","tryCatchPattern":"try:\n    sv.DetectionDataset.from_createml(images_directory_path=d, annotations_path=a)\nexcept ValueError as exc:\n    if \"duplicate entries\" in str(exc):\n        # merge annotations arrays for duplicated images, then retry\n        ...\n    raise","preventionTips":["Deduplicate on resolved paths whenever you concatenate CreateML files.","Remember './a.jpg' and 'a.jpg' are the same image to the loader.","Automate a uniqueness check in CI for generated annotation files."],"tags":["createml","dataset-load","duplicates","data-quality"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}