JuliusBrussee/caveman · error · CatalogError
: unknown field(s)
Error message
{label}: unknown field(s): {', '.join(sorted(unknown))} What it means
A catalog row contains a top-level field not in the allowed schema (REQUIRED_KEYS plus the optional capabilities_verified_at). The validator is strict-allowlist: unknown fields are typos, drifted schema, or unvetted data, so they fail the build rather than being silently ignored. Thrown from validate_row.
Solutions
- Remove or rename the listed unknown field(s) to the schema's snake_case names
- If the data belongs in the row, move it into the allowed `capabilities` mapping or a YAML comment
- If a new top-level field is genuinely needed, add it to TOP_LEVEL_KEYS/REQUIRED_KEYS in validate_catalog.py and to schemas/provider-catalog.schema.json in the same change
- Check the row against an existing valid row in current.yaml for exact field names
Example fix
# before - provider: openai verifiedAt: "2026-07-05T00:00:00Z" # after - provider: openai verified_at: "2026-07-05T00:00:00Z"
Defensive patterns
Strategy: validation
Validate before calling
TOP_LEVEL_KEYS = {"provider","model","region","currency","pricing","capabilities","sources","verified_at","capabilities_verified_at"}
def no_unknown_fields(row: dict) -> bool:
return not (set(row) - TOP_LEVEL_KEYS) Type guard
def has_known_keys_only(row: dict) -> bool:
return set(row).issubset(TOP_LEVEL_KEYS) Try / catch
try:
validate_catalog()
except CatalogError as e:
if "unknown field(s)" in str(e):
rename_or_remove_fields(str(e)) Prevention
- Validate rows against schemas/provider-catalog.schema.json in CI before the Python validator runs
- Use snake_case field names matching existing rows
- Keep free-form notes as YAML comments, not fields
When it happens
Trigger: validate_row sees `set(row) - TOP_LEVEL_KEYS` non-empty, e.g. a row with `verifiedAt` (camelCase), `verification_date`, or a newly invented key like `notes` placed at row level instead of inside capabilities.
Common situations: Renaming a field without updating the schema; camelCase vs snake_case mismatch from a JS-authored script; adding free-form commentary at row level instead of as a YAML comment; schema additions made in one file but not the other.
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
- : missing field(s)
- : unknown pricing field(s)
- : every catalog row must be an object
- catalog is empty
- catalog
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/cb1a36ec74072bed.
Report an issue: GitHub.
Appendix: source
Thrown at shared/provider-catalog/validate_catalog.py:120
if isinstance(value, datetime):
parsed = value
elif isinstance(value, str):
try:
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
except ValueError as error:
raise CatalogError(f"{label}: verified_at must be RFC3339") from error
else:
raise CatalogError(f"{label}: verified_at must be an RFC3339 timestamp")
if parsed.tzinfo is None:
raise CatalogError(f"{label}: verified_at must include a timezone")
return parsed.astimezone(timezone.utc)
def validate_row(row: dict[str, Any], label: str, now: datetime) -> tuple[str, str, str]:
unknown = set(row) - TOP_LEVEL_KEYS
missing = REQUIRED_KEYS - set(row)
if unknown:
raise CatalogError(f"{label}: unknown field(s): {', '.join(sorted(unknown))}")
if missing:
raise CatalogError(f"{label}: missing field(s): {', '.join(sorted(missing))}")
identity: list[str] = []
for field in ("provider", "model", "region"):
value = row[field]
if not isinstance(value, str) or not IDENTIFIER.fullmatch(value):
raise CatalogError(f"{label}: {field} must be a safe non-empty identifier")
identity.append(value)
if row["currency"] != "USD":
raise CatalogError(f"{label}: currency must be USD")
pricing = row["pricing"]
if not isinstance(pricing, dict):
raise CatalogError(f"{label}: pricing must be an object")
pricing_unknown = set(pricing) - PRICING_KEYS
if pricing_unknown:
raise CatalogError(f"{label}: unknown pricing field(s): {', '.join(sorted(pricing_unknown))}")View on GitHub (pinned to 3ee70a1026)