atuinsh/atuin · error

issue in stats day of week query

Error message

issue in stats day of week query

What it means

Panic while compiling the day-of-week histogram query. The guarded builder (database.rs:862-869) emits `strftime('%w', ROUND(timestamp / 1000000000), 'unixepoch') AS day_of_week` plus a count, with `command = ?1` and group_by on the alias — fully static, so sql() Err is an unreachable invariant.

Source

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

        // _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.
        #[allow(clippy::type_complexity)]
        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)
                .map(Self::row_to_history)

View on GitHub (pinned to 15fe1318f1)

Solutions

  1. Revert the sqlbuilder change in Cargo.lock to the last known-good version
  2. Add the day_of_week builder to the CI unit test that asserts all stats queries compile to SQL
  3. If genuinely failing on the pinned version, report upstream with the exact strftime/group_by combination, since that is the most exotic expression of the seven stats queries
Defensive patterns

Strategy: try-catch

Try / catch

let stats = std::panic::catch_unwind(|| {
    tokio::task::block_on(database.stats(&history))
});
let _ = stats.map_err(|_| tracing::error!("stats day-of-week builder panicked"));

Prevention

When it happens

Trigger: Database::stats() after swapping sqlbuilder to a version that rejects something in this chain (commonly group_by on an aliased field or the complex strftime expression in fields()). No database content or user input affects the builder.

Common situations: sqlbuilder major-version bumps during dependency maintenance; a vendored patch changing how group_by/aliases are validated. Not seen on the committed lockfile.

Related errors


AI-assisted analysis of atuinsh/atuin@15fe1318f1 (2026-08-19). Data as JSON: /api/errors/111f74140ff105eb. Report an issue: GitHub.