{"record":{"id":"1d70e0af2043c21c","repo":"atuinsh/atuin","slug":"issue-in-stats-next-query","errorCode":null,"errorMessage":"issue in stats next query","messagePattern":"issue in stats next query","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/atuin-client/src/database.rs","lineNumber":952,"sourceCode":"            .and_where(\"command = ?1\")\n            .group_by(\"day_of_week\");\n\n        // Intentionally format the string with 01 hardcoded. We want the average runtime for the\n        // _entire month_, but will later parse it as a datetime for sorting\n        // Sqlite has no datetime so we cannot do it there, and otherwise sorting will just be a\n        // string sort, which won't be correct.\n        let mut duration_over_time = SqlBuilder::select_from(\"history\");\n        duration_over_time\n            .fields(&[\n                \"strftime('01-%m-%Y', ROUND(timestamp / 1000000000), 'unixepoch') AS month_year\",\n                \"avg(duration) as duration\",\n            ])\n            .and_where(\"command = ?1\")\n            .group_by(\"month_year\")\n            .having(\"duration > 0\");\n\n        let prev = prev.sql().expect(\"issue in stats previous query\");\n        let next = next.sql().expect(\"issue in stats next query\");\n        let total = total.sql().expect(\"issue in stats average query\");\n        let average = average.sql().expect(\"issue in stats previous query\");\n        let exits = exits.sql().expect(\"issue in stats exits query\");\n        let day_of_week = day_of_week.sql().expect(\"issue in stats day of week query\");\n        let duration_over_time = duration_over_time\n            .sql()\n            .expect(\"issue in stats duration over time query\");\n\n        // The queries are all independent, so run them concurrently on the pool.\n        let (prev, next, total, average, exits, day_of_week, duration_over_time): (\n            _,\n            _,\n            (i64,),\n            (f64,),\n            Vec<(i64, i64)>,\n            Vec<(String, i64)>,\n            Vec<(String, f64)>,\n        ) = tokio::try_join!(","sourceCodeStart":934,"sourceCodeEnd":970,"githubUrl":"https://github.com/atuinsh/atuin/blob/202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1/crates/atuin-client/src/database.rs#L934-L970","documentation":"The second of the seven stats expect() panics (database.rs:952), rendering the 'next' builder for `atuin stats`. Identical semantics to its siblings: SqlBuilder::sql() returns Err only when builder misuse leaves an unrenderable state, the fixed query shape means no runtime input can cause it, and the message marks it as an Atuin bug to report. After rendering, all seven queries run concurrently on the pool via tokio::try_join!.","triggerScenarios":"Running `atuin stats` with a development build whose 'next' builder construction was broken by a local change.","commonSituations":"Development-only; a custom/patched Atuin build with a regression in the stats query assembly.","solutions":["Update Atuin and report the panic upstream with a backtrace","Rebuild from a clean checkout to rule out a stale mixed build","Developers: smoke-test `atuin stats` after any change near database.rs:930-960","Add unit coverage rendering every stats builder"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"let handle = std::thread::spawn(move || db.stats());\nif handle.join().is_err() { /* internal stats-query panic: report upstream */ }","preventionTips":["Smoke-test `atuin stats` after development changes near the stats queries","Keep each stats builder independently unit-tested for rendering","Report upstream with the exact panic string and version","Prefer clean rebuilds when bisecting suspected regressions"],"tags":["database","panic","invariant","stats","sqlite","sql-builder","rust","atuin"],"backgroundTag":"internal-invariant-panic","analyzedSha":"202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1","analyzedAt":"2026-08-16T19:30:24.731Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}