JuliusBrussee/caveman · error

%s %s/%s: verified_at is in the future

Error message

%s %s/%s: verified_at is in the future

What it means

Thrown by the catalog YAML loader when an entry's verified_at timestamp lies more than 24 hours in the future (UTC). A future-dated verification would misrepresent when prices were checked, so the loader rejects it; the 24h tolerance absorbs reasonable clock skew.

Source

Thrown at shared/platform/catalog/catalog.go:277

	}
	seen := make(map[string]struct{}, len(decoded))
	for i, entry := range decoded {
		label := fmt.Sprintf("entry %d", i)
		if strings.TrimSpace(entry.Provider) == "" || strings.TrimSpace(entry.Model) == "" || strings.TrimSpace(entry.Region) == "" {
			return nil, fmt.Errorf("%s: provider, model, and region are required", label)
		}
		if entry.Currency != "USD" {
			return nil, fmt.Errorf("%s %s/%s: unsupported currency %q", label, entry.Provider, entry.Model, entry.Currency)
		}
		if !cost.ValidPrice(entry.Pricing) {
			return nil, fmt.Errorf("%s %s/%s: invalid pricing", label, entry.Provider, entry.Model)
		}
		verified, err := time.Parse(time.RFC3339, entry.VerifiedAt)
		if err != nil || verified.IsZero() {
			return nil, fmt.Errorf("%s %s/%s: verified_at must be RFC3339", label, entry.Provider, entry.Model)
		}
		if verified.After(time.Now().UTC().Add(24 * time.Hour)) {
			return nil, fmt.Errorf("%s %s/%s: verified_at is in the future", label, entry.Provider, entry.Model)
		}
		if entry.CapabilitiesVerifiedAt != "" {
			capVerified, err := time.Parse(time.RFC3339, entry.CapabilitiesVerifiedAt)
			if err != nil || capVerified.IsZero() {
				return nil, fmt.Errorf("%s %s/%s: capabilities_verified_at must be RFC3339", label, entry.Provider, entry.Model)
			}
			if capVerified.After(time.Now().UTC().Add(24 * time.Hour)) {
				return nil, fmt.Errorf("%s %s/%s: capabilities_verified_at is in the future", label, entry.Provider, entry.Model)
			}
		}
		if len(entry.Sources) == 0 {
			return nil, fmt.Errorf("%s %s/%s: at least one source is required", label, entry.Provider, entry.Model)
		}
		for _, rawURL := range entry.Sources {
			u, err := url.ParseRequestURI(rawURL)
			if err != nil || u.Scheme != "https" || u.Host == "" {
				return nil, fmt.Errorf("%s %s/%s: invalid HTTPS source %q", label, entry.Provider, entry.Model, rawURL)
			}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Correct the timestamp to the actual verification date (past or within 24h of now).
  2. Regenerate the field from the machine's real clock at verification time: date -u +%Y-%m-%dT%H:%M:%SZ.
  3. If it was a build-host clock issue, fix NTP on that host so generated catalogs aren't future-dated.

Example fix

# before
verified_at: 2027-08-15T00:00:00Z

# after
verified_at: 2026-08-14T18:30:00Z
Defensive patterns

Strategy: validation

Validate before calling

func notFutureBeyond24h(s string) bool {
    t, err := time.Parse(time.RFC3339, s)
    return err == nil && !t.After(time.Now().UTC().Add(24*time.Hour))
}

Try / catch

Fail catalog load at startup; fix the date in data. Do not widen the tolerance in code to work around bad data.

Prevention

When it happens

Trigger: verified_at like "2027-01-01T00:00:00Z" when today is in 2026, or any timestamp more than 24h past time.Now().UTC() — often from a typo in the year, or a machine with a badly wrong clock producing 'now' dates that are ahead for everyone else.

Common situations: Typo'd year (2026 vs 2027); timestamps written on a host whose clock is set months ahead; CI regenerating the catalog with a mocked future time.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/060408d89585bd72. Report an issue: GitHub.