{"record":{"id":"807013849b8f48e1","repo":"atuinsh/atuin","slug":"too-many-entries-in-v1-kv-record","errorCode":null,"errorMessage":"too many entries in v1 kv record","messagePattern":"too many entries in v1 kv record","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/atuin-kv/src/store/record.rs","lineNumber":69,"sourceCode":"                    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            }\n            RecordVersion::V1 => {\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 == 4, \"too many entries in v1 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, mut bytes) = decode::read_str_from_slice(bytes).map_err(error_report)?;\n                let has_value = decode::read_bool(&mut bytes).map_err(error_report)?;\n\n                let (value, bytes) = if has_value {\n                    let (value, bytes) =\n                        decode::read_str_from_slice(bytes).map_err(error_report)?;\n                    (Some(value.to_owned()), bytes)\n                } else {\n                    (None, bytes)\n                };\n\n                if !bytes.is_empty() {\n                    bail!(\"trailing bytes in encoded kvrecord. malformed\");","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/atuinsh/atuin/blob/c0c717ab04c881764bcad4b3d169a507e2432643/crates/atuin-kv/src/store/record.rs#L51-L87","documentation":"A v1 kv record is a msgpack array of exactly 4 fields (namespace, key, and two additional fields introduced in v1). The deserializer rejects any v1 record whose decoded array length is not 4, indicating the payload does not match the v1 schema. This prevents misreading corrupt or older-format data as a valid v1 record.","triggerScenarios":"Deserializing a RecordVersion::V1 kv record whose msgpack payload decodes to an array length other than 4.","commonSituations":"Version skew where an old or newer client writes v1 records with a different shape; corrupted sync data; manual DB edits.","solutions":["Upgrade atuin on all synced machines to identical versions","Delete the malformed v1 record and re-set the kv pair","Fall back/re-sync the kv store from a healthy host","If a pre-release client produced the record, identify and remove it from sync"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"let n = rmp::decode::read_array_len(&mut bytes)?;\nif n != 4 { return Err(\"malformed v1 kv record\".into()); }","typeGuard":null,"tryCatchPattern":"match KvRecord::deserialize(RecordVersion::V1, &data) {\n    Ok(rec) => apply(rec),\n    Err(e) => log::warn!(\"skipping malformed v1 kv record: {e}\"),\n}","preventionTips":["Ensure all clients understand the v1 schema before upgrading records","Avoid mixed stable/pre-release versions in one sync graph","Re-set corrupted keys from a current client","Validate records after restoring from backups"],"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"}