JuliusBrussee/caveman · error · CatalogError
: verified_at must be an RFC3339 timestamp
Error message
{label}: verified_at must be an RFC3339 timestamp What it means
verified_at is neither a YAML-parsed datetime nor a string — it is some other type (int, float, list, bool, etc.). parsed_time only accepts datetime objects or RFC3339 strings, so any other type is rejected outright. This keeps price provenance a real timestamp rather than a number that could be confused with a version.
Solutions
- Change verified_at to an RFC3339 string like `"2026-07-05T00:00:00Z"` (quote it to prevent YAML type coercion)
- If you intended an epoch timestamp, convert it to an ISO-8601 UTC string first
- Check for accidental YAML structure — ensure verified_at maps to a single scalar, not a nested list/mapping
Example fix
# before verified_at: 20260705 # after verified_at: "2026-07-05T00:00:00Z"
Defensive patterns
Strategy: type-guard
Validate before calling
def verified_at_type_ok(row: dict) -> bool:
v = row.get("verified_at")
return isinstance(v, (str, datetime)) Type guard
def is_timestamp_like(value: object) -> bool:
return isinstance(value, str) or isinstance(value, datetime) Try / catch
try:
validate_catalog()
except CatalogError as e:
if "RFC3339 timestamp" in str(e):
coerce_to_iso_string(str(e)) Prevention
- Quote date values in YAML (`verified_at: "2026-07-05T00:00:00Z"`) so YAML cannot coerce them to int
- Never use epoch integers for verified_at
- Check emitted types in sync scripts before writing YAML
When it happens
Trigger: A row sets verified_at to a number (e.g. `verified_at: 20260705`), a boolean, a list, or a YAML date written in a form PyYAML parses as non-datetime non-string. Called from validate_row/validate_catalog via parsed_time.
Common situations: Writing a date as digits without quotes so YAML makes it an int; a script emitting an epoch/unix timestamp; accidentally quoting the wrong field so a list ends up in verified_at.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- : pricing must be an object
- : verified_at must be RFC3339
- : verified_at must include a timezone
- catalog is empty
- catalog
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/3abf45d121cd57f9.
Report an issue: GitHub.
Appendix: source
Thrown at shared/provider-catalog/validate_catalog.py:110
except (OSError, yaml.YAMLError) as error:
raise CatalogError(f"{path}: invalid YAML: {error}") from error
if not isinstance(document, list) or not document:
raise CatalogError(f"{path}: catalog must be a non-empty list")
if not all(isinstance(row, dict) for row in document):
raise CatalogError(f"{path}: every catalog row must be an object")
return document
def parsed_time(value: Any, label: str) -> datetime:
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")View on GitHub (pinned to 3ee70a1026)