atuinsh/atuin · critical

invalid id UUID format in sqlite DB

Error message

invalid id UUID format in sqlite DB

What it means

A deliberate panic in SqliteStore::query_row (record store, V2 sync) when the `id` column of a row in the records SQLite database is not a parseable UUID. The code comment is explicit — 'tbh at this point things are pretty fucked so just panic' — because a non-UUID id means the store table is corrupted or was written by something other than Atuin. Any read path that maps rows (e.g. all_tagged, loading records for sync) will abort the process on the offending row.

Source

Thrown at crates/atuin-client/src/record/sqlite_store.rs:103

        .bind(r.idx as i64)
        .bind(r.host.id.0.as_hyphenated().to_string())
        .bind(r.tag.as_str())
        .bind(r.timestamp as i64)
        .bind(r.version.as_str())
        .bind(r.data.raw.as_str())
        .bind(r.data.cek.as_str())
        .execute(&mut **tx)
        .await?;

        Ok(())
    }

    fn query_row(row: SqliteRow) -> Record<paseto_v4::EncryptedData> {
        let idx: i64 = row.get("idx");
        let timestamp: i64 = row.get("timestamp");

        // tbh at this point things are pretty fucked so just panic
        let id = Uuid::from_str(row.get("id")).expect("invalid id UUID format in sqlite DB");
        let host = Uuid::from_str(row.get("host")).expect("invalid host UUID format in sqlite DB");

        Record {
            id: RecordId(id),
            idx: idx as u64,
            host: Host::new(HostId(host)),
            timestamp: timestamp as u64,
            tag: RecordTag::from(row.get::<String, _>("tag")),
            version: RecordVersion::from(row.get::<String, _>("version")),
            data: paseto_v4::EncryptedData {
                raw: row.get("data"),
                cek: row.get("cek"),
            },
        }
    }

    async fn load_all(&self) -> Result<Vec<Record<paseto_v4::EncryptedData>>> {
        let res = sqlx::query("select * from store ")

View on GitHub (pinned to 202f6ad98e)

Solutions

  1. Restore the records database from a backup (default under ~/.local/share/atuin/)
  2. Find and remove the offending rows before Atuin reads them: select id from store where id not like '________-____-____-____-____________' (or validate with a UUID check), then delete them
  3. If the store is unrecoverable, delete the records DB and re-register/re-sync from another host's copy
  4. Never edit the SQLite files while Atuin or the daemon is running; stop processes first

Example fix

-- before: corrupt rows panic the reader
-- after: locate and remove them (backup first!)
-- sqlite3 ~/.local/share/atuin/records.sqlite3
.backup /tmp/records.bak
DELETE FROM store WHERE id NOT GLOB '????????-????-????-????-????????????';
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check the store table for corrupt ids before Atuin reads it
// sqlite3 ~/.local/share/atuin/records.sqlite3
// SELECT id FROM store WHERE id NOT GLOB '????????-????-????-????-????????????';
// (backup first: .backup /tmp/records.bak; then DELETE the offending rows)

Try / catch

// It is an expect() panic: cannot be caught as an error. Guard by validating the
// data beforehand and keeping backups; if embedding, run record reads on a
// thread and treat join failure as 'corrupt store' → restore/rebuild.

Prevention

When it happens

Trigger: Reading records from a records database whose store.id values are not UUID strings: hand-edited DB, a partial/interrupted external write, disk corruption, another tool writing the table, or a file from an incompatible tool assuming the same schema.

Common situations: Users manually 'fixing' the record store with SQL; restoring an old/partial backup; filesystem damage; running tools that share the SQLite file while Atuin writes; partial file copy between machines.

Related errors


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