JuliusBrussee/caveman · error
native session usage: %w
Error message
native session usage: %w
What it means
Returned by Store.SessionUsage when the aggregate SELECT over the requests table for the given session fails at the database layer. Identity already validated, so causes are environmental: the DB is closed, the requests table is missing/corrupt, or the query hits an I/O error (bad disk, moved file).
Source
Thrown at proxy/internal/store/store.go:646
`SELECT COUNT(*),
COALESCE(SUM(CASE WHEN token_usage_basis = 'provider_complete' THEN 1 ELSE 0 END),0),
COALESCE(SUM(input_tokens),0), COALESCE(SUM(output_tokens),0),
COALESCE(SUM(cached_input_tokens),0), COALESCE(SUM(cache_creation_input_tokens),0),
COALESCE(SUM(reasoning_tokens),0), COALESCE(SUM(total_cost_usd),0),
COALESCE(SUM(savings_usd),0), COALESCE(SUM(compression_tokens_before),0),
COALESCE(SUM(compression_tokens_after),0),
COALESCE(GROUP_CONCAT(DISTINCT NULLIF(compression_token_count_basis,'')),''),
COALESCE(GROUP_CONCAT(DISTINCT NULLIF(session_correlation_basis,'')),'')
FROM requests WHERE session_id = ?`,
sessionID,
).Scan(
&out.Requests, &out.ProviderCompleteRequests, &out.InputTokens, &out.OutputTokens,
&out.CachedInputTokens, &out.CacheCreationInputTokens, &out.ReasoningTokens,
&out.CatalogListPriceSubtotalUSD, &out.InferredSavingsUSD,
&out.CompressionTokensBefore, &out.CompressionTokensAfter, &compressionBases, &correlationBases,
)
if err != nil {
return out, fmt.Errorf("native session usage: %w", err)
}
if out.Requests == 0 {
return out, nil
}
out.Status = "correlated"
if !strings.Contains(correlationBases, ",") {
out.CorrelationBasis = correlationBases
} else {
out.CorrelationBasis = "mixed"
}
if out.ProviderCompleteRequests == out.Requests {
out.TokenUsageCoverage = "provider_complete"
} else {
out.TokenUsageCoverage = "mixed_or_unavailable"
}
if compressionBases == "estimated_engine_o200k" || compressionBases == "legacy_unspecified" {
out.CompressionTokenCountBasis = compressionBases
} else if compressionBases != "" {View on GitHub (pinned to 27d5a3981a)
Solutions
- Ensure the store is still open — do not share a Store across goroutines after Close; open per command if needed
- If the table is missing, the DB came from a foreign/older schema: recreate with store.Open on a fresh path or re-run migrations
- Run sqlite3 <db> 'PRAGMA integrity_check' to detect corruption; .recover or delete and rebuild if it fails
- Read from a stable copy: stop the proxy, copy the file, query the copy
Example fix
# before: stats command against a mid-backup file $ cp ~/.caveman/caveman.db /tmp/db.bak & caveman-proxy stats --db /tmp/db.bak native session usage: disk I/O error # after: quiesce first, then copy, then query $ caveman-proxy stop 2>/dev/null || true $ cp ~/.caveman/caveman.db /tmp/db.bak $ caveman-proxy stats --db /tmp/db.bak
Defensive patterns
Strategy: try-catch
Validate before calling
// Cheap liveness probe before the aggregate
var one int
if err := st.DB().QueryRow("SELECT 1 FROM requests LIMIT 1").Scan(&one); err != nil && err != sql.ErrNoRows {
return fmt.Errorf("requests table unavailable: %w", err)
} Try / catch
snap, err := st.SessionUsage(id)
if err != nil {
if errors.Is(err, sql.ErrConnDone) || strings.Contains(err.Error(), "database is closed") {
// lifecycle bug in caller: re-open the store and retry once
}
if strings.Contains(err.Error(), "no such table") {
// foreign schema: recreate or point at the right DB
}
return err
} Prevention
- Do not call Store methods after Close; scope the Store to the command's lifetime
- Run PRAGMA integrity_check periodically to catch corruption before it surfaces mid-query
- Query a quiesced copy of the DB for offline analytics instead of the live file
When it happens
Trigger: Calling SessionUsage on a Store whose Close() already ran (sql: database is closed), against a DB where the requests table was dropped/renamed by a migration mismatch, or while the file is corrupt/being restored from backup.
Common situations: Querying usage during shutdown races; a stats command pointed at a caveman.db created by an incompatible version; the DB file on a flaky mount returning I/O errors during the scan; reading a partially-copied backup file.
Related errors
- migrate sqlite %q: %w
- ccr: typed object id collision
- memory %s changed during supersede
- memory %s not found
- prefix replacement put: %w
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/2f6b4a8ec769b034.
Report an issue: GitHub.