{"record":{"id":"9171f341ed096e8e","repo":"Pumpkin-MC/Pumpkin","slug":"invalid-utf-8-sequence","errorCode":null,"errorMessage":"Invalid UTF-8 sequence","messagePattern":"Invalid UTF-8 sequence","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/pumpkin-protocol/src/serial/deserializer.rs","lineNumber":169,"sourceCode":"\nimpl PacketRead for String {\n    fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {\n        const MAX_STRING_LENGTH: usize = 32767;\n\n        let len = VarUInt::read(reader)?.0 as usize;\n\n        if len > MAX_STRING_LENGTH {\n            return Err(Error::new(\n                ErrorKind::InvalidData,\n                format!(\"String length {len} exceeds maximum of {MAX_STRING_LENGTH}\"),\n            ));\n        }\n\n        let mut buf = vec![0u8; len];\n        reader.read_exact(&mut buf)?;\n\n        Self::from_utf8(buf)\n            .map_err(|_| Error::new(ErrorKind::InvalidData, \"Invalid UTF-8 sequence\"))\n    }\n}\n\nimpl<T: PacketRead> PacketRead for Vec<T> {\n    fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {\n        let len = VarUInt::read(reader)?.0 as usize;\n        if len > 65536 {\n            return Err(Error::new(\n                ErrorKind::InvalidData,\n                format!(\"Vector length {len} exceeds limit of 65536\"),\n            ));\n        }\n        let mut buf = Self::with_capacity(len.min(1024));\n        for _ in 0..len {\n            buf.push(T::read(reader)?);\n        }\n        Ok(buf)\n    }","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/Pumpkin-MC/Pumpkin/blob/8d4639e25a57c15e47448ec327c780d41bbf2356/crates/pumpkin-protocol/src/serial/deserializer.rs#L151-L187","documentation":"Thrown by `Self::from_utf8` in the `PacketRead for String` impl when the bytes read for the string are not valid UTF-8. The protocol mandates UTF-8 strings, so undecodable bytes cause a hard error. This typically indicates data corruption or a stream desync rather than a normal runtime condition.","triggerScenarios":"read() reads `len` bytes after a valid VarUInt prefix, but those bytes fail String::from_utf8 — corrupted stream, wrong length prefix, or non-UTF-8 encoding from the peer.","commonSituations":"Desynced packet stream reading binary payload bytes as a string; malicious packets with arbitrary bytes; reading a legacy/compressed payload incorrectly.","solutions":["Check the stream for desync before this point (all prior fields parsed correctly?)","Validate packet bytes with a UTF-8 validator or std::str::from_utf8 in a debug path to locate the offset","Drop or reject the offending packet; resynchronize or reconnect","Confirm the peer encodes strings as UTF-8 per the protocol version"],"exampleFix":"// before\nlet s: String = reader.read()?;\n// after\nif let Err(e) = String::read(&mut reader) {\n    log::warn!(\"non-UTF-8 string in packet: {e}\");\n    return Err(PacketError::Malformed);\n}","handlingStrategy":"try-catch","validationCode":"// validate UTF-8 in debug builds at decode boundaries\ndebug_assert!(std::str::from_utf8(buf).is_ok(), \"non-UTF-8 payload\");","typeGuard":"fn is_utf8(b: &[u8]) -> bool { std::str::from_utf8(b).is_ok() }","tryCatchPattern":"match String::read(&mut reader) {\n    Ok(s) => s,\n    Err(e) => { log::warn!(\"utf8 decode failed: {e}\"); return Err(PacketError::Malformed); }\n}","preventionTips":["Reject packets from peers with mismatched protocol versions","Detect desync early: validate each field and abort on first error","Never trust raw network bytes; treat decode failures as connection-fatal"],"tags":["protocol","utf-8","serialization"],"backgroundTag":"invalid-argument-format","analyzedSha":"8d4639e25a57c15e47448ec327c780d41bbf2356","analyzedAt":"2026-09-09T15:32:22.916Z","contentChangedAt":"2026-09-09T15:32:22.916Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}