JuliusBrussee/caveman · warning
invalid --since %q (want RFC3339): %w
Error message
invalid --since %q (want RFC3339): %w
What it means
Returned by Store.ObserveSummarySince when the optional --since value is non-empty but does not parse as RFC3339. The store timestamps rows in UTC using RFC3339-derived formatting, so the cutoff must be an exact RFC3339 timestamp like 2026-01-02T15:04:05Z or with an explicit offset (2026-01-02T10:04:05-05:00).
Source
Thrown at proxy/internal/store/store.go:741
out.Basis = "inferred"
return out, nil
}
// ObserveSummarySince returns the compact observe-estimate object, optionally
// filtered to rows at or after an RFC3339 instant (the wrap session start). It
// mixes the observe-only would-have-saved numbers with the real compression cut so
// one call serves both the "would have cut" (observe) and "cut" (compress) session
// lines. Everything it reports is `inferred`; savings_usd is whatever was truly
// booked (0 in observe mode), and would_save_usd stays nil unless a priced row
// produced one.
func (s *Store) ObserveSummarySince(since string) (ObserveSummary, error) {
out := ObserveSummary{Basis: "inferred", TokenAccounting: map[string]int64{}}
where := ""
var args []any
if trimmed := strings.TrimSpace(since); trimmed != "" {
t, err := time.Parse(time.RFC3339, trimmed)
if err != nil {
return out, fmt.Errorf("invalid --since %q (want RFC3339): %w", trimmed, err)
}
where = " WHERE ts >= ?"
args = append(args, t.UTC().Format(storeTSLayout))
}
var usdCount int64
var usdSum float64
row := s.db.QueryRow(`SELECT COUNT(*), COALESCE(SUM(input_tokens),0), COALESCE(SUM(would_save_tokens),0),
COALESCE(SUM(compression_tokens_before),0), COALESCE(SUM(compression_tokens_after),0),
COALESCE(SUM(compression_tokens_before - compression_tokens_after),0),
COALESCE(SUM(savings_usd),0), COUNT(would_save_usd), COALESCE(SUM(would_save_usd),0),
COALESCE(SUM(cached_input_tokens),0), COALESCE(SUM(cache_creation_input_tokens),0),
COALESCE(SUM(CASE WHEN cache_bust <> 0 THEN 1 ELSE 0 END),0),
COALESCE(SUM(CASE WHEN compression_eligible <> 0 THEN 1 ELSE 0 END),0)
FROM requests`+where, args...)
if err := row.Scan(&out.Spans, &out.TokensIn, &out.WouldSaveTokens,
&out.CompressionTokensBefore, &out.CompressionTokensAfter, &out.CompressionTokensSaved,
&out.SavingsUSD, &usdCount, &usdSum,
&out.CachedInputTokens, &out.CacheCreationInputTokens,View on GitHub (pinned to 27d5a3981a)
Solutions
- Use a full RFC3339 timestamp with timezone: 2026-01-02T15:04:05Z or 2026-01-02T15:04:05+02:00
- In scripts, generate it: date -u +%Y-%m-%dT%H:%M:%SZ
- If you only want date granularity, expand it explicitly: 2026-01-02T00:00:00Z
- Catch the error and show the offending value plus the expected format to the user
Example fix
# before caveman-proxy stats --since 2026-01-02 invalid --since "2026-01-02" (want RFC3339) # after caveman-proxy stats --since 2026-01-02T00:00:00Z # or generated: --since "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
Defensive patterns
Strategy: validation
Validate before calling
if since != "" {
if _, err := time.Parse(time.RFC3339, strings.TrimSpace(since)); err != nil {
return fmt.Errorf("--since must be RFC3339, e.g. %s", time.Now().UTC().Add(-24*time.Hour).Format(time.RFC3339))
}
} Type guard
func isRFC3339(s string) bool {
s = strings.TrimSpace(s)
if s == "" { return true } // optional flag
_, err := time.Parse(time.RFC3339, s)
return err == nil
} Try / catch
sum, err := st.ObserveSummarySince(since)
if err != nil && strings.Contains(err.Error(), "invalid --since") {
return fmt.Errorf("bad --since: pass an RFC3339 timestamp like 2026-01-02T00:00:00Z")
} Prevention
- Generate --since in scripts with date -u +%Y-%m-%dT%H:%M:%SZ
- Remember RFC3339 requires a timezone (Z or ±hh:mm); date-only and space-separated forms fail
- Date-granularity needs T00:00:00Z appended explicitly
When it happens
Trigger: Passing a date-only string ('2026-01-02'), a legacy timestamp format ('2026-01-02 15:04:05'), a missing timezone, or garbage into the --since flag consumed by ObserveSummarySince. Empty/whitespace strings are fine (no filter); anything else must be strict RFC3339.
Common situations: Users habitually typing 'YYYY-MM-DD' from other tools' date flags; passing Unix epoch seconds or ISO-with-space from scripts; a timezone-less local timestamp like '2026-01-02T15:04:05' (RFC3339 requires an offset); copy-pasting a timestamp that contains a trailing space or quote.
Related errors
- cache-replay: -trace and positive request/token/trace/respon
- report path is required
- export directory is required
- invalid agent evidence identity
- ${key} is required
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/aabfa526b9b0d580.
Report an issue: GitHub.