{"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/900007c48045867e7f44b0f9bc55ad9dbe99ee0d/crates/atuin-kv/src/store/record.rs#L51-L87","documentation":"A V1 KV record must be a MsgPack array of exactly 4 entries (namespace, key, value, plus the V1-added field such as a timestamp). The deserializer enforces nfields == 4 for version V1 and rejects any other count to keep the wire format strict.","triggerScenarios":"Deserializing a record tagged V1 whose array length != 4 — e.g. a V0 payload mislabeled as V1, an encoder omitting the fourth field, or one adding extra fields.","commonSituations":"Mixed-version KV clients in a sync mesh, manual record construction with the wrong version tag, or corruption during storage/sync.","solutions":["Re-write the entry so the version tag matches the field count (V0 -> 3 fields, V1 -> 4 fields).","Fix the encoder to emit exactly 4 entries when writing V1 records.","Upgrade older clients that cannot read V1 records to a compatible Atuin version."],"exampleFix":"// before: tagged V1 but encoded as (namespace, key, value)\n// after:  encode::to_bytes(&(namespace, key, value, timestamp)) with RecordVersion::V1","handlingStrategy":"validation","validationCode":"let value: rmpv::Value = rmpv::decode::read_value(&mut cursor)?;\n// v1 kv record requires exactly 4 fields\nassert_eq!(value.as_array().map(|a| a.len()), Some(4));","typeGuard":"fn is_well_formed_v1_kv(payload: &[u8]) -> bool {\n    rmpv::decode::read_value(&mut std::io::Cursor::new(payload))\n        .ok()\n        .and_then(|v| v.as_array().map(|a| a.len() == 4))\n        .unwrap_or(false)\n}","tryCatchPattern":"match KvRecord::deserialize(&data) {\n    Ok(rec) => apply(rec),\n    Err(e) if e.to_string().contains(\"too many entries in v1\") => {\n        log::warn(\"v1 kv record field-count mismatch: {e}\");\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Emit all four V1 fields (including the timestamp) when writing V1 records","Do not label a 3-field payload as V1; that is a V0 record","Write encode/decode round-trip tests per record version"],"tags":["serialization","msgpack","kv"],"backgroundTag":"schema-validation-failed","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"}