atuinsh/atuin · error

issue in stats exits query

Error message

issue in stats exits query

What it means

The fifth stats expect() panic (database.rs:955), rendering the 'exits' builder for `atuin stats`. Same family and same semantics: the query shape is hard-coded (exit-code aggregation over history), sql() failure is impossible from user input, and the expect exists to convert 'builder misused' into a loud, reportable crash. All seven rendered strings are then executed concurrently with tokio::try_join!.

Source

Thrown at crates/atuin-client/src/database.rs:955

        // Intentionally format the string with 01 hardcoded. We want the average runtime for the
        // _entire month_, but will later parse it as a datetime for sorting
        // Sqlite has no datetime so we cannot do it there, and otherwise sorting will just be a
        // string sort, which won't be correct.
        let mut duration_over_time = SqlBuilder::select_from("history");
        duration_over_time
            .fields(&[
                "strftime('01-%m-%Y', ROUND(timestamp / 1000000000), 'unixepoch') AS month_year",
                "avg(duration) as duration",
            ])
            .and_where("command = ?1")
            .group_by("month_year")
            .having("duration > 0");

        let prev = prev.sql().expect("issue in stats previous query");
        let next = next.sql().expect("issue in stats next query");
        let total = total.sql().expect("issue in stats average query");
        let average = average.sql().expect("issue in stats previous query");
        let exits = exits.sql().expect("issue in stats exits query");
        let day_of_week = day_of_week.sql().expect("issue in stats day of week query");
        let duration_over_time = duration_over_time
            .sql()
            .expect("issue in stats duration over time query");

        // The queries are all independent, so run them concurrently on the pool.
        let (prev, next, total, average, exits, day_of_week, duration_over_time): (
            _,
            _,
            (i64,),
            (f64,),
            Vec<(i64, i64)>,
            Vec<(String, i64)>,
            Vec<(String, f64)>,
        ) = tokio::try_join!(
            sqlx::query(sqlx::AssertSqlSafe(prev))
                .bind(h.timestamp.unix_timestamp_nanos() as i64)
                .bind(&h.session)

View on GitHub (pinned to 202f6ad98e)

Solutions

  1. Update Atuin and report the panic with the backtrace
  2. Rule out a stale custom build by rebuilding from a clean tree
  3. Developers: keep stats builders covered by rendering unit tests
  4. Run `atuin stats` as a smoke test after touching the stats code
Defensive patterns

Strategy: validation

Try / catch

let handle = std::thread::spawn(move || db.stats());
if handle.join().is_err() { /* exits-query builder panic: report upstream */ }

Prevention

When it happens

Trigger: Running `atuin stats` against a build with a regression in the exits builder construction.

Common situations: Development-only occurrences; users should treat any sighting as an upstream bug and update/report.

Related errors


AI-assisted analysis of atuinsh/atuin@202f6ad98e (2026-08-16). Data as JSON: /api/errors/9b4540487fa76edc. Report an issue: GitHub.