JuliusBrussee/caveman · error · CatalogError
{label}: verified_at is in the future
Error message
{label}: verified_at is in the future What it means
Raised by validate_row() in the provider-catalog validator when a row's verified_at timestamp is strictly later than the validation time (now, default datetime.now(timezone.utc)). verified_at is price provenance — the sole input to catalogVersion() embedded in signed receipts — so a future date would attest a price check that has not happened yet. The comparison happens after parsed_time() normalizes the value to UTC, so both naive-skew and timezone-skew land here.
Source
Thrown at shared/provider-catalog/validate_catalog.py:164
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"]
if not isinstance(sources, list) or not sources:
raise CatalogError(f"{label}: sources must be a non-empty list")
if any(not isinstance(source, str) or not source.startswith("https://") for source in sources):
raise CatalogError(f"{label}: every source must be HTTPS")
verified_at = parsed_time(row["verified_at"], label)
if verified_at > now:
raise CatalogError(f"{label}: verified_at is in the future")
if verified_at < now - timedelta(days=120):
raise CatalogError(f"{label}: verified_at is older than 120 days")
return identity[0], identity[1], identity[2]
def check_review_markers(text: str, label: str) -> None:
"""Refuse a catalog that still carries an unreviewed sync proposal.
YAML comments are invisible to the parsed rows, so this reads the raw file:
a rubber-stamped merge must not be able to advance price provenance while
the line saying "nobody has confirmed this yet" is still in the file.
"""
offending = [
index + 1
for index, line in enumerate(text.splitlines())
if line.lstrip().startswith(REVIEW_MARKER)
]
if offending:View on GitHub (pinned to 27d5a3981a)
Solutions
- Set verified_at to the actual UTC date you checked the vendor pricing page (RFC3339 with timezone, e.g. 2026-08-15T00:00:00Z); it must be <= now.
- If the timestamp came from scripts/catalog_sync_modelsdev.py, re-check the rows against their cited sources and correct the date before merging.
- If this fires in a test, pass a `now` that is at or after the fixture's verified_at (validate_catalog(now=...)).
- If the machine clock is wrong (VM, CI runner drift), fix the clock via NTP and re-run; do not bump the date to silence it.
Example fix
# current.yaml (before) verified_at: "2026-09-01T00:00:00Z" # dated in the future # after verified_at: "2026-08-15T00:00:00Z" # the day prices were actually checked
Defensive patterns
Strategy: validation
Validate before calling
from datetime import datetime, timezone
def verified_at_is_not_future(verified_at: str) -> bool:
try:
ts = datetime.fromisoformat(verified_at.replace("Z", "+00:00"))
except ValueError:
return False
return ts.tzinfo is not None and ts.astimezone(timezone.utc) <= datetime.now(timezone.utc) Try / catch
try:
validate_catalog()
except CatalogError as e:
# message names the row label; fix the row's verified_at, do not catch-and-continue
raise SystemExit(f"catalog invalid: {e}") Prevention
- Write verified_at as the UTC date you actually checked the vendor page, never a planned/launch date.
- Run validate_catalog.py in CI and pre-commit so future-dated rows fail before merge.
- Keep test fixtures' verified_at parametric (computed from now) rather than hardcoded.
When it happens
Trigger: Running validate_catalog.py (or validate_catalog(now=...)) when any row in catalog/current.yaml has verified_at later than the check time: a sync script stamping the proposal date instead of the check date, a hand-edit copying tomorrow's date, a test passing a fixed `now` earlier than the fixture's verified_at, or a machine clock behind the author's clock (timestamp written on a fast clock, validated on a slow one).
Common situations: Running the catalog validator in CI or on a fresh checkout right after an automated catalog sync proposed changes; timezone confusion where a local-time timestamp without offset would fail earlier ('must include a timezone') but a +00:00 future date reaches this check; fixtures in tests using hardcoded dates that drift into the future relative to a frozen `now`.
Related errors
- {label}: verified_at is older than 120 days
- {label}: unreviewed sync proposal marker on line(s) {', '.jo
- {label}: pricing changed without a new verified_at snapshot
- {label}: dropped or replaced a source from its immutable sna
- caveman agent: value is not canonically serializable
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/cbc98e8a56a966cd.
Report an issue: GitHub.