{"record":{"id":"83827749a6fc8e9a","repo":"atuinsh/atuin","slug":"too-many-entries-in-v0-dotfiles-var-delete-record","errorCode":null,"errorMessage":"too many entries in v0 dotfiles var delete record","messagePattern":"too many entries in v0 dotfiles var delete record","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/atuin-dotfiles/src/store/var.rs","lineNumber":70,"sourceCode":"        }\n\n        match version {\n            RecordVersion::V0 => {\n                let mut bytes = decode::Bytes::new(&data.0);\n\n                let record_type = decode::read_u8(&mut bytes).map_err(error_report)?;\n\n                match record_type {\n                    // create\n                    0 => {\n                        let env = Var::deserialize(&mut bytes)?;\n                        Ok(Self::Create(env))\n                    }\n\n                    // delete\n                    1 => {\n                        let nfields = decode::read_array_len(&mut bytes).map_err(error_report)?;\n                        ensure!(nfields == 1, \"too many entries in v0 dotfiles var delete record\");\n\n                        let bytes = bytes.remaining_slice();\n\n                        let (key, bytes) =\n                            decode::read_str_from_slice(bytes).map_err(error_report)?;\n\n                        if !bytes.is_empty() {\n                            bail!(\"trailing bytes in encoded dotfiles var record. malformed\");\n                        }\n\n                        Ok(Self::Delete(key.to_owned()))\n                    }\n\n                    n => {\n                        bail!(\"unknown Dotfiles var record type {n}\");\n                    }\n                }\n            }","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/atuinsh/atuin/blob/900007c48045867e7f44b0f9bc55ad9dbe99ee0d/crates/atuin-dotfiles/src/store/var.rs#L52-L88","documentation":"The v0 dotfiles var delete record must be a MsgPack array of exactly 1 entry (the variable name). The deserializer enforces nfields == 1 after the delete discriminator and rejects other counts. Extra entries signal malformed or schema-incompatible data.","triggerScenarios":"Deserializing a v0 var record with discriminator 1 (delete) whose array length is not 1 — e.g. a record written by an incompatible encoder or with corrupted bytes.","commonSituations":"Version skew between synced Atuin clients, manually written records, or corruption in the record store.","solutions":["Re-delete the var with the current CLI: `atuin dotfiles var delete <name>`.","Correct the encoder to emit a single-entry array for delete.","Upgrade all sync peers to matching Atuin versions."],"exampleFix":"// before: encode::to_bytes(&(name, extra))\n// after:  encode::to_bytes(&(name,))","handlingStrategy":"validation","validationCode":"let value: rmpv::Value = rmpv::decode::read_value(&mut cursor)?;\n// var delete variant: discriminator 1 requires exactly 1 field\nassert_eq!(value.as_array().map(|a| a.len()), Some(1));","typeGuard":"fn is_well_formed_var_delete(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() == 1))\n        .unwrap_or(false)\n}","tryCatchPattern":"match ShellVar::deserialize(&bytes) {\n    Ok(var) => handle(var),\n    Err(e) if e.to_string().contains(\"too many entries\") => {\n        log::warn(\"dropping malformed var delete record: {e}\");\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Use ShellVar::serialize rather than manual MsgPack encoding","Keep Atuin versions aligned across syncing machines","Add round-trip unit tests for every record variant"],"tags":["serialization","msgpack","vars"],"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"}