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

  1. Validate that the client encodes strings as UTF-8 before sending.
  2. Check for stream misalignment: an earlier field read with the wrong size shifts subsequent string boundaries.
  3. Inspect the failing bytes; if they are legacy-encoded, convert the sender to UTF-8.
  4. 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

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


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)