{"record":{"id":"f8fb7ecc59cc3b2f","repo":"atuinsh/atuin","slug":"invalid-id-uuid-format-in-sqlite-db","errorCode":null,"errorMessage":"invalid id UUID format in sqlite DB","messagePattern":"invalid id UUID format in sqlite DB","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/atuin-client/src/record/sqlite_store.rs","lineNumber":103,"sourceCode":"        .bind(r.idx as i64)\n        .bind(r.host.id.0.as_hyphenated().to_string())\n        .bind(r.tag.as_str())\n        .bind(r.timestamp as i64)\n        .bind(r.version.as_str())\n        .bind(r.data.raw.as_str())\n        .bind(r.data.cek.as_str())\n        .execute(&mut **tx)\n        .await?;\n\n        Ok(())\n    }\n\n    fn query_row(row: SqliteRow) -> Record<paseto_v4::EncryptedData> {\n        let idx: i64 = row.get(\"idx\");\n        let timestamp: i64 = row.get(\"timestamp\");\n\n        // tbh at this point things are pretty fucked so just panic\n        let id = Uuid::from_str(row.get(\"id\")).expect(\"invalid id UUID format in sqlite DB\");\n        let host = Uuid::from_str(row.get(\"host\")).expect(\"invalid host UUID format in sqlite DB\");\n\n        Record {\n            id: RecordId(id),\n            idx: idx as u64,\n            host: Host::new(HostId(host)),\n            timestamp: timestamp as u64,\n            tag: RecordTag::from(row.get::<String, _>(\"tag\")),\n            version: RecordVersion::from(row.get::<String, _>(\"version\")),\n            data: paseto_v4::EncryptedData {\n                raw: row.get(\"data\"),\n                cek: row.get(\"cek\"),\n            },\n        }\n    }\n\n    async fn load_all(&self) -> Result<Vec<Record<paseto_v4::EncryptedData>>> {\n        let res = sqlx::query(\"select * from store \")","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/atuinsh/atuin/blob/202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1/crates/atuin-client/src/record/sqlite_store.rs#L85-L121","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Restore the records database from a backup (default under ~/.local/share/atuin/)","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","If the store is unrecoverable, delete the records DB and re-register/re-sync from another host's copy","Never edit the SQLite files while Atuin or the daemon is running; stop processes first"],"exampleFix":"-- before: corrupt rows panic the reader\n-- after: locate and remove them (backup first!)\n-- sqlite3 ~/.local/share/atuin/records.sqlite3\n.backup /tmp/records.bak\nDELETE FROM store WHERE id NOT GLOB '????????-????-????-????-????????????';","handlingStrategy":"validation","validationCode":"// Pre-check the store table for corrupt ids before Atuin reads it\n// sqlite3 ~/.local/share/atuin/records.sqlite3\n// SELECT id FROM store WHERE id NOT GLOB '????????-????-????-????-????????????';\n// (backup first: .backup /tmp/records.bak; then DELETE the offending rows)","typeGuard":null,"tryCatchPattern":"// It is an expect() panic: cannot be caught as an error. Guard by validating the\n// data beforehand and keeping backups; if embedding, run record reads on a\n// thread and treat join failure as 'corrupt store' → restore/rebuild.","preventionTips":["Never hand-edit records.sqlite3 while Atuin or the daemon runs","Keep periodic backups of ~/.local/share/atuin","Validate UUID-shaped id/host columns after any manual DB surgery or restore","Avoid restoring partial/copy-in-progress database files between machines"],"tags":["database","corruption","panic","uuid","sqlite","sync","rust","atuin"],"backgroundTag":"database-corruption","analyzedSha":"202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1","analyzedAt":"2026-08-16T19:30:24.731Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}