Pumpkin-MC/Pumpkin · error
String::from_utf8 error
Error message
String::from_utf8 error
What it means
This error wraps a String::from_utf8 failure when converting decoded bytes of a user-data string into a Rust String. It means the byte sequence in the packet is not valid UTF-8, so the library rejects the packet rather than producing lossy text.
Solutions
- Validate that the client encodes strings as UTF-8 before sending.
- Check for stream misalignment: an earlier field read with the wrong size shifts subsequent string boundaries.
- Inspect the failing bytes; if they are legacy-encoded, convert the sender to UTF-8.
- On the server side, consider rejecting the offending client packet cleanly and logging the peer.
Example fix
// sender before: raw bytes, non-UTF-8 writer.write_all(&latin1_bytes)?; // after writer.write_all(String::from_utf8(latin1_bytes_lossy)?.as_bytes())?;
Defensive patterns
Strategy: try-catch
Validate before calling
fn is_valid_utf8(bytes: &[u8]) -> bool {
std::str::from_utf8(bytes).is_ok()
} Type guard
fn as_utf8(bytes: &[u8]) -> Option<&str> {
std::str::from_utf8(bytes).ok()
} Try / catch
match read_user_data_strings(&mut cursor) {
Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
log::warn!("non-UTF-8 string in item user data: {e}; dropping packet");
}
other => other?,
} Prevention
- Always encode strings as UTF-8 on the client
- Validate field alignment: a misread prior field splits multi-byte characters
- Test with non-ASCII block names to catch encoding bugs early
When it happens
Trigger: Triggered in read_user_data_strings after read_exact loads str_len bytes and String::from_utf8 fails because the bytes are not valid UTF-8.
Common situations: Clients sending non-UTF-8 encoded text (e.g. legacy encodings), corrupted packets, stream misalignment slicing a multi-byte UTF-8 character.
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
- user_data_len exceeds 1MB limit
- extra_data_len exceeds 1MB limit
- Invalid ContainerName ID
- item string array length out of bounds
- Nbt read error
AI-assisted analysis of Pumpkin-MC/Pumpkin@8d4639e25a (2026-09-09).
Data as JSON: /api/errors/3d249a6f3512af6f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/pumpkin-protocol/src/bedrock/network_item.rs:589
"item string array length out of bounds",
));
}
let mut values = Vec::with_capacity((len as usize).min(32));
for _ in 0..len {
let mut length = [0; 2];
reader.read_exact(&mut length)?;
let str_len = usize::from(u16::from_be_bytes(length));
if str_len > 32767 {
return Err(Error::new(
std::io::ErrorKind::InvalidData,
"item string too long",
));
}
let mut bytes = vec![0; str_len];
reader.read_exact(&mut bytes)?;
values.push(
String::from_utf8(bytes)
.map_err(|error| Error::new(std::io::ErrorKind::InvalidData, error))?,
);
}
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);View on GitHub (pinned to 8d4639e25a)