JuliusBrussee/caveman · error · CatalogError
: unknown pricing field(s)
Error message
{label}: unknown pricing field(s): {', '.join(sorted(pricing_unknown))} What it means
The `pricing` object contains a key outside the allowlisted PRICING_KEYS set (the twelve known per-million rate/threshold fields). Like the top-level schema, pricing is strict-allowlist so misspelled or invented rate names cannot silently produce zero-cost math. Thrown from validate_row.
Solutions
- Rename the listed key(s) to the exact allowed names (e.g. `input_per_million`, `output_per_million`, `cache_read_input_per_million`)
- Check PRICING_KEYS in validate_catalog.py for the exact spelling of each field
- If a genuinely new pricing field is needed, add it to PRICING_KEYS and schemas/provider-catalog.schema.json in the same PR
- Map third-party field names to the schema's snake_case names in any sync script
Example fix
# before pricing: input_per_million_tokens: 2.5 # after pricing: input_per_million: 2.5
Defensive patterns
Strategy: validation
Validate before calling
PRICING_KEYS = {"input_per_million","output_per_million","cache_read_input_per_million","cache_write_input_per_million","cache_write_1h_input_per_million","reasoning_output_per_million","batch_discount_fraction","cache_storage_per_million_tokens_hour","long_context_threshold_tokens","long_context_threshold_inclusive","long_context_input_multiplier","long_context_output_multiplier"}
def pricing_keys_ok(row: dict) -> bool:
p = row.get("pricing")
return isinstance(p, dict) and not (set(p) - PRICING_KEYS) Type guard
def has_known_pricing_keys(pricing: dict) -> bool:
return set(pricing).issubset(PRICING_KEYS) Try / catch
try:
validate_catalog()
except CatalogError as e:
if "unknown pricing field(s)" in str(e):
rename_pricing_keys(str(e)) Prevention
- Copy key names verbatim from an existing row or PRICING_KEYS
- Map third-party/camelCase names to schema names in sync scripts
- Validate against schemas/provider-catalog.schema.json which lists the same allowed pricing keys
When it happens
Trigger: pricing has keys like `input_per_million_tokens`, `inputPerMillion`, `output`, `cache_read`, or a renamed/typo'd variant of an allowed key, making `set(pricing) - PRICING_KEYS` non-empty.
Common situations: Typo in an allowed key name; a script using camelCase or a third-party API's field names; inventing a new pricing field without registering it in PRICING_KEYS and schemas/provider-catalog.schema.json; copying field names from a provider's API docs instead of this schema.
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)
- : pricing must be an object
- : unknown field(s)
- : every catalog row must be an object
- catalog is empty
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/a4c522b56ebb7629.
Report an issue: GitHub.
Appendix: source
Thrown at shared/provider-catalog/validate_catalog.py:138
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))}")
for required in ("input_per_million", "output_per_million"):
if required not in pricing:
raise CatalogError(f"{label}: pricing.{required} is required")
for field, value in pricing.items():
if value is None or field == "long_context_threshold_inclusive":
if field == "long_context_threshold_inclusive" and value is not None and not isinstance(value, bool):
raise CatalogError(f"{label}: pricing.{field} must be boolean or null")
continue
if isinstance(value, bool) or not isinstance(value, (int, float)):
raise CatalogError(f"{label}: pricing.{field} must be numeric or null")
if not math.isfinite(value) or value < 0:
raise CatalogError(f"{label}: pricing.{field} must be finite and nonnegative")
if field == "batch_discount_fraction" and value > 1:
raise CatalogError(f"{label}: pricing.batch_discount_fraction must be <= 1")
if not isinstance(row["capabilities"], dict):
raise CatalogError(f"{label}: capabilities must be an object")
sources = row["sources"]View on GitHub (pinned to 3ee70a1026)