{"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/27d5a3981a347890211bb1bf2439e5c821a63bc9/shared/provider-catalog/validate_catalog.py#L202-L238","documentation":"Raised by validate_catalog() when two rows in current.yaml share the same (provider, model, region) identity tuple — the three-part key validate_row() returns and the loop accumulates in `seen`. The catalog is keyed by that tuple; a duplicate makes lookups ambiguous (which row answers a price query), so validation fails fast with the duplicated identity in the message.","triggerScenarios":"Adding a row for a provider/model/region combination that already exists (e.g. a second 'openai/gpt-4o/us' entry), a sync script appending rather than replacing rows, or a copy-paste edit that forgot to change region or model.","commonSituations":"Manual catalog edits copying a neighboring row as a template; automated sync tools that append updates instead of upserting; merge conflicts resolved by keeping both sides' rows.","solutions":["Search current.yaml for the duplicated provider/model/region tuple named in the message and delete or differentiate the redundant row.","If you meant to update pricing, edit the EXISTING row (bumping verified_at and minting a snapshot) instead of adding a second entry.","If regions genuinely differ (e.g. 'us' vs 'global'), fix the region field on the row you intended to change."],"exampleFix":"# before — two identical identities\n- {provider: openai, model: gpt-4o, region: us, ...}\n- {provider: openai, model: gpt-4o, region: us, ...}  # duplicate\n\n# after — one row, pricing edited in place\n- {provider: openai, model: gpt-4o, region: us, pricing: {...updated...}, verified_at: \"2026-08-15T00:00:00Z\"}","handlingStrategy":"validation","validationCode":"def duplicate_identities(rows: list[dict]) -> list[tuple]:\n    seen, dupes = set(), []\n    for row in rows:\n        key = (row.get(\"provider\"), row.get(\"model\"), row.get(\"region\"))\n        if key in seen:\n            dupes.append(key)\n        seen.add(key)\n    return dupes","typeGuard":null,"tryCatchPattern":"try:\n    validate_catalog()\nexcept CatalogError as e:\n    if \"duplicate identity\" in str(e):\n        dedupe_by_identity(\"current.yaml\")  # keep/merge into the verified row\n    raise","preventionTips":["Before adding a row, grep current.yaml for the provider/model/region tuple.","Make sync scripts upsert by identity instead of appending.","Resolve merge conflicts by picking one side per identity, never both."],"tags":["validation","catalog","duplicates","data-integrity"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}