JuliusBrussee/caveman · error · CatalogError
: duplicate identity
Error message
{label}: duplicate identity {'/'.join(identity)} What it means
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 '/'.
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
Example fix
# before (current.yaml) - provider: openai model: gpt-4o monthly_input: 2.50 - provider: openai model: gpt-4o monthly_input: 2.75 # after (deduplicated) - provider: openai model: gpt-4o monthly_input: 2.75
Defensive patterns
Strategy: validation
Validate before calling
def check_unique_identities(rows):
seen = set()
for i, row in enumerate(rows):
identity = (row["provider"], row["model"], row["unit"])
if identity in seen:
raise ValueError(f"row {i+1}: duplicate identity {'/'.join(identity)}")
seen.add(identity) Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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).
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- catalog
- duplicate provider/model/region row
- : currency must be USD
- : dropped or replaced a source from its immutable snapshot…
- : must be a safe non-empty identifier
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/364aca4d39ed2afc.
Report an issue: GitHub.
Appendix: source
Thrown at shared/provider-catalog/validate_catalog.py:220
identity["price_affecting_capabilities"] = {
key: capabilities[key] for key in PRICE_AFFECTING_CAPABILITY_KEYS if key in capabilities
}
return identity
def validate_catalog(now: datetime | None = None) -> None:
check_time = now or datetime.now(timezone.utc)
current_path = CATALOG_DIR / "current.yaml"
current = load_yaml(current_path)
check_review_markers(current_path.read_text(encoding="utf-8"), "current.yaml")
snapshots: dict[str, list[dict[str, Any]]] = {}
seen: set[tuple[str, str, str]] = set()
for index, row in enumerate(current):
label = f"current.yaml row {index + 1}"
identity = validate_row(row, label, check_time)
if identity in seen:
raise CatalogError(f"{label}: duplicate identity {'/'.join(identity)}")
seen.add(identity)
verified = parsed_time(row["verified_at"], label).date().isoformat()
snapshot = snapshots.setdefault(
verified,
load_yaml(CATALOG_DIR / f"{verified}.yaml"),
)
identity = pricing_identity(row)
matched = next(
(snap_row for snap_row in snapshot if pricing_identity(snap_row) == identity),
None,
)
if matched is None:
raise CatalogError(
f"{label}: pricing changed without a new verified_at snapshot version (checked catalog/{verified}.yaml)"
)
# sources is excluded from pricing_identity so a capability citation can
# be added without minting a new price-dated snapshot, but a PRICINGView on GitHub (pinned to 3ee70a1026)