{"record":{"id":"2f6b4a8ec769b034","repo":"JuliusBrussee/caveman","slug":"native-session-usage-w","errorCode":null,"errorMessage":"native session usage: %w","messagePattern":"native session usage: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/store/store.go","lineNumber":646,"sourceCode":"\t\t`SELECT COUNT(*),\n\t\t        COALESCE(SUM(CASE WHEN token_usage_basis = 'provider_complete' THEN 1 ELSE 0 END),0),\n\t\t        COALESCE(SUM(input_tokens),0), COALESCE(SUM(output_tokens),0),\n\t\t        COALESCE(SUM(cached_input_tokens),0), COALESCE(SUM(cache_creation_input_tokens),0),\n\t\t        COALESCE(SUM(reasoning_tokens),0), COALESCE(SUM(total_cost_usd),0),\n\t\t        COALESCE(SUM(savings_usd),0), COALESCE(SUM(compression_tokens_before),0),\n\t\t        COALESCE(SUM(compression_tokens_after),0),\n\t\t        COALESCE(GROUP_CONCAT(DISTINCT NULLIF(compression_token_count_basis,'')),''),\n\t\t        COALESCE(GROUP_CONCAT(DISTINCT NULLIF(session_correlation_basis,'')),'')\n\t\t   FROM requests WHERE session_id = ?`,\n\t\tsessionID,\n\t).Scan(\n\t\t&out.Requests, &out.ProviderCompleteRequests, &out.InputTokens, &out.OutputTokens,\n\t\t&out.CachedInputTokens, &out.CacheCreationInputTokens, &out.ReasoningTokens,\n\t\t&out.CatalogListPriceSubtotalUSD, &out.InferredSavingsUSD,\n\t\t&out.CompressionTokensBefore, &out.CompressionTokensAfter, &compressionBases, &correlationBases,\n\t)\n\tif err != nil {\n\t\treturn out, fmt.Errorf(\"native session usage: %w\", err)\n\t}\n\tif out.Requests == 0 {\n\t\treturn out, nil\n\t}\n\tout.Status = \"correlated\"\n\tif !strings.Contains(correlationBases, \",\") {\n\t\tout.CorrelationBasis = correlationBases\n\t} else {\n\t\tout.CorrelationBasis = \"mixed\"\n\t}\n\tif out.ProviderCompleteRequests == out.Requests {\n\t\tout.TokenUsageCoverage = \"provider_complete\"\n\t} else {\n\t\tout.TokenUsageCoverage = \"mixed_or_unavailable\"\n\t}\n\tif compressionBases == \"estimated_engine_o200k\" || compressionBases == \"legacy_unspecified\" {\n\t\tout.CompressionTokenCountBasis = compressionBases\n\t} else if compressionBases != \"\" {","sourceCodeStart":628,"sourceCodeEnd":664,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/proxy/internal/store/store.go#L628-L664","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before: stats command against a mid-backup file\n$ cp ~/.caveman/caveman.db /tmp/db.bak & caveman-proxy stats --db /tmp/db.bak\nnative session usage: disk I/O error\n\n# after: quiesce first, then copy, then query\n$ caveman-proxy stop 2>/dev/null || true\n$ cp ~/.caveman/caveman.db /tmp/db.bak\n$ caveman-proxy stats --db /tmp/db.bak","handlingStrategy":"try-catch","validationCode":"// Cheap liveness probe before the aggregate\nvar one int\nif err := st.DB().QueryRow(\"SELECT 1 FROM requests LIMIT 1\").Scan(&one); err != nil && err != sql.ErrNoRows {\n    return fmt.Errorf(\"requests table unavailable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"snap, err := st.SessionUsage(id)\nif err != nil {\n    if errors.Is(err, sql.ErrConnDone) || strings.Contains(err.Error(), \"database is closed\") {\n        // lifecycle bug in caller: re-open the store and retry once\n    }\n    if strings.Contains(err.Error(), \"no such table\") {\n        // foreign schema: recreate or point at the right DB\n    }\n    return err\n}","preventionTips":["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"],"tags":["sqlite","database","lifecycle","go"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}