{"record":{"id":"364aca4d39ed2afc","repo":"JuliusBrussee/caveman","slug":"label-duplicate-identity-join-identity","errorCode":null,"errorMessage":"{label}: duplicate identity {'/'.join(identity)}","messagePattern":"(.+?): duplicate identity (.+?)","errorType":"validation","errorClass":"CatalogError","httpStatus":null,"severity":"error","filePath":"shared/provider-catalog/validate_catalog.py","lineNumber":220,"sourceCode":"    identity[\"price_affecting_capabilities\"] = {\n        key: capabilities[key] for key in PRICE_AFFECTING_CAPABILITY_KEYS if key in capabilities\n    }\n    return identity\n\n\ndef validate_catalog(now: datetime | None = None) -> None:\n    check_time = now or datetime.now(timezone.utc)\n    current_path = CATALOG_DIR / \"current.yaml\"\n    current = load_yaml(current_path)\n    check_review_markers(current_path.read_text(encoding=\"utf-8\"), \"current.yaml\")\n    snapshots: dict[str, list[dict[str, Any]]] = {}\n    seen: set[tuple[str, str, str]] = set()\n\n    for index, row in enumerate(current):\n        label = f\"current.yaml row {index + 1}\"\n        identity = validate_row(row, label, check_time)\n        if identity in seen:\n            raise CatalogError(f\"{label}: duplicate identity {'/'.join(identity)}\")\n        seen.add(identity)\n\n        verified = parsed_time(row[\"verified_at\"], label).date().isoformat()\n        snapshot = snapshots.setdefault(\n            verified,\n            load_yaml(CATALOG_DIR / f\"{verified}.yaml\"),\n        )\n        identity = pricing_identity(row)\n        matched = next(\n            (snap_row for snap_row in snapshot if pricing_identity(snap_row) == identity),\n            None,\n        )\n        if matched is None:\n            raise CatalogError(\n                f\"{label}: pricing changed without a new verified_at snapshot version (checked catalog/{verified}.yaml)\"\n            )\n        # sources is excluded from pricing_identity so a capability citation can\n        # be added without minting a new price-dated snapshot, but a PRICING","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/provider-catalog/validate_catalog.py#L202-L238","documentation":"validate_catalog.py derives an identity triple for every row of current.yaml via validate_row and rejects the catalog if two rows share the same identity, since the identity uniquely keys a provider/model/price entry. Duplicate identities would make snapshot matching ambiguous downstream (pricing_identity lookups), so the validator fails fast naming the offending row and the colliding identity joined with '/'.","triggerScenarios":"Running validate_catalog when two rows in current.yaml produce the identical (provider, model, unit or equivalent) identity tuple from validate_row; the second occurrence raises with label 'current.yaml row N' and the joined identity.","commonSituations":"A copy-paste of a model row with only the price changed; an automated sync re-inserting a row that already exists; merging two branches that both added the same model entry; a typo in the field that would otherwise distinguish rows (e.g. same provider/model spelling).","solutions":["Locate the reported row in current.yaml and the earlier row with the same identity; delete or correct the duplicate","If both rows are intentional variants, differentiate the identity fields (e.g. distinct model name or unit) so they no longer collide","Re-run the sync tool so it deduplicates instead of re-adding the row","Re-run validate_catalog to confirm the identity set is unique"],"exampleFix":"# before (current.yaml)\n- provider: openai\n  model: gpt-4o\n  monthly_input: 2.50\n- provider: openai\n  model: gpt-4o\n  monthly_input: 2.75\n# after (deduplicated)\n- provider: openai\n  model: gpt-4o\n  monthly_input: 2.75","handlingStrategy":"validation","validationCode":"def check_unique_identities(rows):\n    seen = set()\n    for i, row in enumerate(rows):\n        identity = (row[\"provider\"], row[\"model\"], row[\"unit\"])\n        if identity in seen:\n            raise ValueError(f\"row {i+1}: duplicate identity {'/'.join(identity)}\")\n        seen.add(identity)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Generate new rows via the sync tooling, which deduplicates, instead of hand-copying existing entries","Run validate_catalog locally before pushing catalog changes","When merging branches that both touched the catalog, re-run the sync to reconcile duplicates","Grep for the model name before adding a new row"],"tags":["validation","catalog","duplicate-detection"],"backgroundTag":"schema-validation-failed","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}