Pumpkin-MC/Pumpkin · error
Nbt read error
Error message
Nbt read error
What it means
Thrown when parsing the NBT payload embedded in an item's user data fails. For version -1 user data the library reads a version byte and then Nbt::read via NbtReadHelperBedrock; any NBT parse error (bad tag, truncated data, unsupported version) is mapped to this InvalidData error.
Solutions
- Verify client and server Bedrock protocol versions match (NBT encoding changed between versions).
- Validate that the item's serialized NBT is well-formed using an NBT debugger on the sender side.
- Check that the full packet was received; truncated user data leads to NBT read failures.
- If a custom tool generates the item data, confirm it emits network little-endian NBT compatible with NbtReadHelperBedrock.
Example fix
// before: writing disk-format NBT into the packet let nbt = Nbt::write_disk_format(&value); // after let nbt = Nbt::write_network_bedrock(&value); // network little-endian, headerless
Defensive patterns
Strategy: try-catch
Validate before calling
fn nbt_version_is_supported(version: i16) -> bool {
version == -1 // only -1 signals an embedded NBT payload; others default
} Try / catch
match read_user_data(&mut cursor, is_shield) {
Err(e) if e.to_string().contains("Nbt read error") => {
log::warn!("malformed NBT in item user data: {e}; rejecting item");
// fall back to a default item or disconnect the peer
}
other => other?,
} Prevention
- Use the correct network (little-endian) NBT encoding for Bedrock packets
- Ensure the full packet payload arrives before parsing (check frame length)
- Test round-trip serialization of item NBT between your client version and server
When it happens
Trigger: Triggered in read_user_data when nbt_version == -1 and Nbt::read returns an error: malformed NBT tags, truncated compound data, or an unsupported NBT version byte.
Common situations: Third-party clients/tools producing non-standard NBT, corrupted packets, protocol version mismatch causing NBT version negotiation differences, network truncation of the item payload.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Failed to decode varint - value too large
- Failed to decode varlong - value too large
- user_data_len exceeds 1MB limit
- extra_data_len exceeds 1MB limit
- Invalid ContainerName ID
AI-assisted analysis of Pumpkin-MC/Pumpkin@8d4639e25a (2026-09-09).
Data as JSON: /api/errors/9e5bebc381f2caef.
Report an issue: GitHub.
Appendix: source
Thrown at crates/pumpkin-protocol/src/bedrock/network_item.rs:609
}
Ok(values)
}
fn read_user_data(
user_data: Vec<u8>,
is_shield: bool,
) -> Result<(Nbt, Vec<String>, Vec<String>, i64), Error> {
if user_data.is_empty() {
return Ok((Nbt::default(), Vec::new(), Vec::new(), 0));
}
let mut cursor = std::io::Cursor::new(user_data);
let nbt_version = i16::read(&mut cursor)?;
let nbt_data = if nbt_version == -1 {
let _version = i8::read(&mut cursor)?;
let mut nbt_reader = NbtReadHelperBedrock::new(&mut cursor);
Nbt::read(&mut nbt_reader)
.map_err(|error| Error::new(std::io::ErrorKind::InvalidData, error))?
} else {
Nbt::default()
};
let place_on_blocks = read_user_data_strings(&mut cursor)?;
let destroy_blocks = read_user_data_strings(&mut cursor)?;
let shield_blocking_tick = if is_shield {
i64::read(&mut cursor)?
} else {
0
};
Ok((
nbt_data,
place_on_blocks,
destroy_blocks,
shield_blocking_tick,
))
}
View on GitHub (pinned to 8d4639e25a)