atuinsh/atuin · error

trailing bytes in encoded script record. malformed

Error message

trailing bytes in encoded script record. malformed

What it means

The script record decoder reads id, name, description, and finally the script body as length-prefixed strings, then requires the payload to be fully consumed. Remaining bytes indicate the payload does not match the expected script record layout, so it bails. This guards the binary format contract.

Solutions

  1. Delete and re-save the affected script so it is re-encoded cleanly
  2. Verify encoder and decoder agree on field order and length prefixes
  3. Check the record tag is a script record before decoding
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the payload decodes to four strings (id, name, description, script) with no leftovers
// fn plausible_script_record(payload: &[u8]) -> bool {
//     let mut b = payload;
//     for _ in 0..4 {
//         match decode::read_str_from_slice(b) { Ok((_, r)) => b = r, Err(_) => return false }
//     }
//     b.is_empty()
// }

Prevention

When it happens

Trigger: Deserializing a script record payload with trailing bytes after the script body — corrupted record data, encoder/decoder layout drift, or the wrong payload type passed to this decoder.

Common situations: Corrupted local record store; decode mismatch after a scripts format change; syncing partial or damaged records.

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/ed51117416455b0d. Report an issue: GitHub.

Appendix: source

Thrown at crates/atuin-scripts/src/store/script.rs:93

        let (description, bytes) = decode::read_str_from_slice(bytes).unwrap();
        let (shebang, bytes) = decode::read_str_from_slice(bytes).unwrap();

        let mut bytes = Bytes::new(bytes);
        let tags_len = decode::read_array_len(&mut bytes).unwrap();

        let mut bytes = bytes.remaining_slice();

        let mut tags = Vec::new();
        for _ in 0..tags_len {
            let (tag, remaining) = decode::read_str_from_slice(bytes).unwrap();
            tags.push(tag.to_owned());
            bytes = remaining;
        }

        let (script, bytes) = decode::read_str_from_slice(bytes).unwrap();

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

        Ok(Self {
            id: Uuid::parse_str(id).unwrap(),
            name: name.to_owned(),
            description: description.to_owned(),
            shebang: shebang.to_owned(),
            tags,
            script: script.to_owned(),
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]

View on GitHub (pinned to 900007c480)