{"record":{"id":"5286c47105b6c596","repo":"atuinsh/atuin","slug":"unknown-historyrecord-type-n","errorCode":null,"errorMessage":"unknown HistoryRecord type {n}","messagePattern":"unknown HistoryRecord type (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/atuin-client/src/history/store.rs","lineNumber":121,"sourceCode":"                Ok(Self::Create(record))\n            }\n\n            // 1 -> HistoryRecord::Delete\n            1 => {\n                let bytes = bytes.remaining_slice();\n                let (id, bytes) = decode::read_str_from_slice(bytes).map_err(error_report)?;\n\n                if !bytes.is_empty() {\n                    bail!(\n                        \"trailing bytes decoding HistoryRecord::Delete - malformed? got {bytes:?}\"\n                    );\n                }\n\n                Ok(Self::Delete(id.parse()?))\n            }\n\n            n => {\n                bail!(\"unknown HistoryRecord type {n}\");\n            }\n        }\n    }\n}\n\n/// How many entries `incremental_build` holds in memory, and the most it puts into a single\n/// `save_bulk`/`delete_rows` transaction.\nconst BUILD_BATCH_SIZE: NonZeroUsize = NonZeroUsize::new(5000).unwrap();\n\n/// How many records `incremental_build` decodes concurrently. Decoding is read-then-decrypt per\n/// record; overlapping the reads keeps the record store's pool busy without unbounded fan-out.\n/// Kept under the store's connection pool size so decodes don't starve other readers.\nconst DECODE_CONCURRENCY: usize = 4;\n\nimpl HistoryStore {\n    #[must_use]\n    pub fn new(store: SqliteStore, host_id: HostId, encryption_key: paseto_v4::Key) -> Self {\n        Self {","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/atuinsh/atuin/blob/c0c717ab04c881764bcad4b3d169a507e2432643/crates/atuin-client/src/history/store.rs#L103-L139","documentation":"Decoder guard in HistoryRecord::deserialize: the record store decoded a history record whose leading tag byte is neither 0 (Create) nor 1 (Delete). This indicates data corruption, a truncated/garbled encrypted payload, or a record written by a newer/older Atuin version using an undocumented type byte — the wire format has diverged from what this client understands.","triggerScenarios":"Deserializing a record written by a newer atuin version that introduced new HistoryRecord variants, or reading corrupted bytes where the tag field is garbage.","commonSituations":"Mixed atuin versions across synced machines; record store corrupted by partial writes.","solutions":["Upgrade atuin on all machines to the newest version","Re-sync the local record store from the Hub if data is damaged","Pin identical atuin versions across devices that share sync"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_supported_tag(tag: u64) -> bool {\n    matches!(tag, 0 | 1) // known HistoryRecord variants\n}","tryCatchPattern":"match HistoryRecord::deserialize(bytes) {\n    Ok(rec) => apply(rec),\n    Err(e) if e.to_string().contains(\"unknown HistoryRecord type\") => {\n        log::warn!(\"record from newer client version; upgrade atuin\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Upgrade all machines sharing sync to the same atuin version","Watch release notes for record-format additions before partial upgrades"],"tags":["serialization","versioning","record-store"],"backgroundTag":"invalid-enum-value","analyzedSha":"c0c717ab04c881764bcad4b3d169a507e2432643","analyzedAt":"2026-09-12T07:40:01.341Z","contentChangedAt":"2026-09-12T07:40:01.341Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}