{"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/// Records appended to the store per transaction by [`HistoryStore::push_records`]. Each chunk is\n/// encrypted before its write lock is taken, so this bounds both how long a concurrent writer can\n/// wait on the lock and how much work a lost race throws away.\nconst APPEND_BATCH_SIZE: usize = 1000;\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;","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/atuinsh/atuin/blob/900007c48045867e7f44b0f9bc55ad9dbe99ee0d/crates/atuin-client/src/history/store.rs#L103-L139","documentation":"`HistoryRecord::deserialize` only knows record-type bytes 0 (Create) and 1 (Delete). Any other leading type byte `n` is rejected with \"unknown HistoryRecord type {n}\", guarding against records from newer or incompatible protocol versions.","triggerScenarios":"Deserializing a history record whose first byte is not 0 or 1 — typically a record type added in a newer atuin version being read by an older client, or a corrupted/truncated payload shifting byte alignment.","commonSituations":"Downgraded atuin CLI reading a record store written by a newer version; syncing with a peer on a different atuin version; binary corruption in the local record DB.","solutions":["Upgrade atuin to the latest version on the machine showing the error so it understands newer record types","Ensure all devices in the sync network run compatible atuin versions","Check whether the record store was written by a newer version (avoid downgrading across record-format changes)","If corruption is suspected, re-sync the affected records from the server"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match record_decode_result {\n    Err(e) if e.to_string().contains(\"unknown HistoryRecord type\") => {\n        eprintln!(\"Record from newer atuin version; upgrade CLI before syncing\");\n    }\n    other => other?,\n}","preventionTips":["Avoid running older atuin binaries against record stores written by newer versions","Upgrade all machines in the sync network together","Pin atuin versions in managed environments"],"tags":["serialization","sync","version-compatibility"],"backgroundTag":"unsupported-enum-value","analyzedSha":"900007c48045867e7f44b0f9bc55ad9dbe99ee0d","analyzedAt":"2026-09-19T12:52:51.491Z","contentChangedAt":"2026-09-19T12:52:51.491Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}