{"record":{"id":"3e981dd38b3a3511","repo":"atuinsh/atuin","slug":"too-many-entries-in-v0-kv-record","errorCode":null,"errorMessage":"too many entries in v0 kv record","messagePattern":"too many entries in v0 kv record","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/atuin-kv/src/store/record.rs","lineNumber":46,"sourceCode":"            encode::write_str(&mut output, value)?;\n        }\n\n        Ok(DecryptedData(output))\n    }\n\n    pub fn deserialize(data: &DecryptedData, version: &RecordVersion) -> Result<Self> {\n        use rmp::decode;\n\n        fn error_report<E: std::fmt::Debug>(err: E) -> eyre::Report {\n            eyre!(\"{err:?}\")\n        }\n\n        match version {\n            RecordVersion::V0 => {\n                let mut bytes = decode::Bytes::new(&data.0);\n\n                let nfields = decode::read_array_len(&mut bytes).map_err(error_report)?;\n                ensure!(nfields == 3, \"too many entries in v0 kv record\");\n\n                let bytes = bytes.remaining_slice();\n\n                let (namespace, bytes) =\n                    decode::read_str_from_slice(bytes).map_err(error_report)?;\n                let (key, bytes) = decode::read_str_from_slice(bytes).map_err(error_report)?;\n                let (value, bytes) = decode::read_str_from_slice(bytes).map_err(error_report)?;\n\n                if !bytes.is_empty() {\n                    bail!(\"trailing bytes in encoded kvrecord. malformed\");\n                }\n\n                Ok(Self {\n                    namespace: namespace.to_owned(),\n                    key: key.to_owned(),\n                    value: Some(value.to_owned()),\n                })\n            }","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/atuinsh/atuin/blob/c0c717ab04c881764bcad4b3d169a507e2432643/crates/atuin-kv/src/store/record.rs#L28-L64","documentation":"A v0 kv record is encoded as a msgpack array of exactly 3 fields (namespace, key, value). The kv store deserializer reads the array length and rejects any record that does not have exactly 3 entries, treating it as malformed. This enforces the v0 on-disk/wire schema for the synced key-value store.","triggerScenarios":"Deserializing a RecordVersion::V0 kv record whose msgpack payload decodes to an array length other than 3.","commonSituations":"Records synced from a newer client (different schema) into an older reader; corrupted record payloads; third-party writes to the kv record store.","solutions":["Upgrade all atuin clients sharing the kv store to the same version","Delete the bad kv record and re-set the key with `atuin kv set`","Re-sync the kv store from a known-good machine","Inspect the record store DB row if the problem is isolated"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"let n = rmp::decode::read_array_len(&mut bytes)?;\nif n != 3 { return Err(\"malformed v0 kv record\".into()); }","typeGuard":null,"tryCatchPattern":"match KvRecord::deserialize(RecordVersion::V0, &data) {\n    Ok(rec) => apply(rec),\n    Err(e) => log::warn!(\"skipping malformed kv record: {e}\"),\n}","preventionTips":["Keep kv-writing clients on the same atuin version","Re-set keys with `atuin kv set` rather than editing records","Don't let pre-release clients write to a shared store","Validate payloads when migrating data between stores"],"tags":["msgpack","deserialization","kv","record-store","versioning"],"backgroundTag":"schema-validation-failed","analyzedSha":"c0c717ab04c881764bcad4b3d169a507e2432643","analyzedAt":"2026-09-12T07:40:01.341Z","contentChangedAt":"2026-09-12T07:40:01.341Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}