JuliusBrussee/caveman · error · CatalogError
: dropped or replaced a source from its immutable snapshot…
Error message
{label}: dropped or replaced a source from its immutable snapshot catalog/{verified}.yaml without a new verified_at (snapshot had {sorted(snapshot_sources)}, current has {sorted(row['sources'])}) What it means
Snapshot files catalog/{verified}.yaml are immutable price-dated records. A row's sources set in current.yaml must be a superset of the sources recorded in its snapshot: existing (pricing) citations may be added to but never silently dropped or replaced while verified_at stays put. The check mirrors the Go isSubset check in catalog_test.go and reports both sets so the diff is obvious.
Solutions
- Restore the missing source(s) listed in the snapshot set to the row's sources in current.yaml
- If the source genuinely must be replaced, bump verified_at and mint a new catalog/{date}.yaml snapshot containing the new sources
- Re-run the sync tool if it is responsible for mangling the sources list
- Re-run validate_catalog to confirm snapshot_sources is now a subset of the current sources
Example fix
# before (current.yaml) sources: - https://new-pricing-page.example.com # after (restored snapshot source) sources: - https://official-pricing.example.com - https://new-pricing-page.example.com
Defensive patterns
Strategy: validation
Validate before calling
def sources_preserved(snapshot_row, current_row):
snap = set(snapshot_row.get("sources") or [])
return snap.issubset(set(current_row["sources"])) Prevention
- Treat snapshot sources as append-only while verified_at is unchanged
- When replacing a citation, bump verified_at and mint a new snapshot instead of swapping in place
- Let the sync tool own the sources list; avoid manual reordering or reformatting
- Review sources diffs explicitly in catalog PRs
When it happens
Trigger: Running validate_catalog after removing or swapping a source URL from a row's sources list while verified_at is unchanged; the snapshot's sources set fails issubset against the current row's sources and the error prints snapshot vs current sorted source lists.
Common situations: Cleaning up 'stale' citation URLs that were actually part of the audited snapshot; a sync tool rewrote the sources list in a different order or format; branch merge dropped a citation added at verification time; replacing a primary source link with a 'better' one without re-verifying prices.
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
- : duplicate identity
- : must be a safe non-empty identifier
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/ee5c5ee67dd9bf10.
Report an issue: GitHub.
Appendix: source
Thrown at shared/provider-catalog/validate_catalog.py:243
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 PRICING
# citation must never be silently swapped or dropped while verified_at
# stays put. Mirrors the Go isSubset check in catalog_test.go.
snapshot_sources = set(matched.get("sources") or [])
if not snapshot_sources.issubset(set(row["sources"])):
raise CatalogError(
f"{label}: dropped or replaced a source from its immutable snapshot "
f"catalog/{verified}.yaml without a new verified_at "
f"(snapshot had {sorted(snapshot_sources)}, current has {sorted(row['sources'])})"
)
def main() -> int:
try:
validate_catalog()
except CatalogError as error:
print(f"provider catalog invalid: {error}", file=sys.stderr)
return 1
print("provider catalog valid: current rows are fresh, sourced, and snapshot-backed")
return 0
if __name__ == "__main__":
raise SystemExit(main())View on GitHub (pinned to 3ee70a1026)