atuinsh/atuin · error

trailing bytes in encoded kvrecord. malformed

Error message

trailing bytes in encoded kvrecord. malformed

What it means

The KV record decoder for Set records reads namespace, key, and value as length-prefixed strings and requires the payload to be fully consumed. Leftover bytes mean the payload does not match the expected Set-record layout, so decoding fails. This catches corrupt or misaligned binary payloads.

Solutions

  1. Delete the affected KV record and re-set the key so it is re-encoded correctly
  2. Ensure encoder and decoder versions agree on the payload layout
  3. Confirm the record tag/field matches before feeding it to the KV decoder
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the payload decodes to exactly three strings with no leftovers
// fn plausible_kv_set(payload: &[u8]) -> bool {
//     decode::read_str_from_slice(payload).ok()
//         .and_then(|(_, b)| decode::read_str_from_slice(b).ok())
//         .and_then(|(_, b)| decode::read_str_from_slice(b).ok())
//         .map(|(_, rest)| rest.is_empty())
//         .unwrap_or(false)
// }

Prevention

When it happens

Trigger: Deserializing a KV Set record whose payload has extra bytes after the value string — corrupted store data, an encoder/decoder layout mismatch, or the wrong payload type passed to the decoder.

Common situations: Corrupted SQLite record store; records re-encoded by a different atuin-kv version; accidental decoding of an alias/var/script payload with the KV decoder.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19). Data as JSON: /api/errors/fa70ac95ef624725. Report an issue: GitHub.

Appendix: source

Thrown at crates/atuin-kv/src/store/record.rs:56

            eyre!("{err:?}")
        }

        match version {
            RecordVersion::V0 => {
                let mut bytes = decode::Bytes::new(&data.0);

                let nfields = decode::read_array_len(&mut bytes).map_err(error_report)?;
                ensure!(nfields == 3, "too many entries in v0 kv record");

                let bytes = bytes.remaining_slice();

                let (namespace, bytes) =
                    decode::read_str_from_slice(bytes).map_err(error_report)?;
                let (key, bytes) = decode::read_str_from_slice(bytes).map_err(error_report)?;
                let (value, bytes) = decode::read_str_from_slice(bytes).map_err(error_report)?;

                if !bytes.is_empty() {
                    bail!("trailing bytes in encoded kvrecord. malformed");
                }

                Ok(Self {
                    namespace: namespace.to_owned(),
                    key: key.to_owned(),
                    value: Some(value.to_owned()),
                })
            }
            RecordVersion::V1 => {
                let mut bytes = decode::Bytes::new(&data.0);

                let nfields = decode::read_array_len(&mut bytes).map_err(error_report)?;
                ensure!(nfields == 4, "too many entries in v1 kv record");

                let bytes = bytes.remaining_slice();

                let (namespace, bytes) =
                    decode::read_str_from_slice(bytes).map_err(error_report)?;

View on GitHub (pinned to 900007c480)