JuliusBrussee/caveman · error · CatalogError
: verified_at must be RFC3339
Error message
{label}: verified_at must be RFC3339 What it means
verified_at was given as a string, but datetime.fromisoformat (with `Z` normalized to `+00:00`) could not parse it. The validator requires RFC3339-formatted timestamps so it can anchor each row to a dated immutable snapshot; an unparseable date proves nothing about when prices were checked. Thrown from parsed_time.
Solutions
- Rewrite verified_at as full RFC3339/ISO-8601 with timezone, e.g. `2026-07-05T00:00:00Z`
- Zero-pad month/day/hour digits (`2026-7-5` -> `2026-07-05`)
- Replace locale formats like 07/05/2026 or 'July 5, 2026' with ISO format
- If the value came from a sync script, fix the script's date formatting (e.g. `datetime.now(timezone.utc).isoformat()`)
Example fix
# before verified_at: 7/5/2026 # after verified_at: "2026-07-05T00:00:00Z"
Defensive patterns
Strategy: validation
Validate before calling
from datetime import datetime
def is_rfc3339(value: str) -> bool:
try:
return datetime.fromisoformat(value.replace("Z", "+00:00")).tzinfo is not None
except ValueError:
return False Type guard
def is_timestamp(value: object) -> bool:
return isinstance(value, str) and is_rfc3339(value) or isinstance(value, datetime) Try / catch
try:
validate_catalog()
except CatalogError as e:
if "verified_at must be RFC3339" in str(e):
fix_date_format(str(e)) Prevention
- Always write dates as `YYYY-MM-DDTHH:MM:SSZ`
- Generate timestamps with datetime.now(timezone.utc).isoformat() in scripts
- Zero-pad all date components
When it happens
Trigger: A row's verified_at string is not ISO/RFC3339 parseable: e.g. `2026-1-5`, `July 5 2026`, `2026/07/05`, `2026-07-05 14:00` with odd formatting, or a locale-formatted date pasted into current.yaml or a dated snapshot row.
Common situations: Typing the date by hand instead of using ISO format; a sync script emitting a human-readable date; copying a date from a provider's pricing page in US format (MM/DD/YYYY); missing zero-padding.
Related errors
- : verified_at must be an RFC3339 timestamp
- : verified_at must include a timezone
- Aider config uses inline/scalar read; use block-list form…
- catalog is empty
- catalog
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/756d340c7abe790c.
Report an issue: GitHub.
Appendix: source
Thrown at shared/provider-catalog/validate_catalog.py:108
try:
document = yaml.safe_load(path.read_text(encoding="utf-8"))
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]View on GitHub (pinned to 3ee70a1026)