JuliusBrussee/caveman · error

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

Error message

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

What it means

Thrown by the catalog YAML loader when the optional capabilities_verified_at timestamp is more than 24 hours in the future (UTC). Same staleness/lying guard as verified_at, applied to the capabilities check date.

Source

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

			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)
			}
		}
		key := entry.Provider + "\x00" + entry.Model + "\x00" + entry.Region
		if _, duplicate := seen[key]; duplicate {
			return nil, fmt.Errorf("duplicate provider/model/region row %s/%s@%s", entry.Provider, entry.Model, entry.Region)
		}
		seen[key] = struct{}{}
	}
	return decoded, nil

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Set the field to the real capabilities-verification date (past or within 24h).
  2. Or delete the field if capabilities verification hasn't happened yet.
  3. Fix the generating host's clock (NTP) so future-dated rows stop appearing.

Example fix

# before
capabilities_verified_at: 2027-01-01T00:00:00Z

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

Strategy: validation

Validate before calling

if entry.CapabilitiesVerifiedAt != "" {
    t, _ := time.Parse(time.RFC3339, entry.CapabilitiesVerifiedAt)
    if t.After(time.Now().UTC().Add(24 * time.Hour)) {
        return fmt.Errorf("capabilities_verified_at is future-dated")
    }
}

Try / catch

Fail catalog load at startup; fix the timestamp or drop the field.

Prevention

When it happens

Trigger: capabilities_verified_at set beyond now+24h — a typo'd year, or generated on a clock-skewed host.

Common situations: Copy-paste from a template row with a placeholder future date; regenerated catalog on a machine with a wrong system clock.

Related errors


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