{"record":{"id":"77cd668c58b76c4e","repo":"Pumpkin-MC/Pumpkin","slug":"eof-tried-to-read-0-but-no-bytes-left-to-consum","errorCode":null,"errorMessage":"EOF, Tried to read {0} but No bytes left to consume","messagePattern":"EOF, Tried to read (.+?) but No bytes left to consume","errorType":"exception","errorClass":"ReadingError","httpStatus":null,"severity":"info","filePath":"crates/pumpkin-protocol/src/ser/mod.rs","lineNumber":21,"sourceCode":"use std::io::{Read, Write};\n\nuse crate::{\n    FixedBitSet,\n    codec::{\n        bit_set::BitSet, var_int::VarInt, var_long::VarLong, var_uint::VarUInt, var_ulong::VarULong,\n    },\n};\n\nuse pumpkin_nbt::{\n    compound::NbtCompound, deserializer::NbtReadHelper, serializer::NbtWriteHelperJava, tag::NbtTag,\n};\nuse pumpkin_util::math::position::BlockPos;\nuse pumpkin_util::{text::TextComponent, version::JavaMinecraftVersion};\nuse thiserror::Error;\n\n#[derive(Debug, Error)]\npub enum ReadingError {\n    #[error(\"EOF, Tried to read {0} but No bytes left to consume\")]\n    CleanEOF(String),\n    #[error(\"incomplete: {0}\")]\n    Incomplete(String),\n    #[error(\"too large: {0}\")]\n    TooLarge(String),\n    #[error(\"{0}\")]\n    Message(String),\n}\n\nimpl serde::de::Error for ReadingError {\n    fn custom<T: std::fmt::Display>(msg: T) -> Self {\n        Self::Message(msg.to_string())\n    }\n}\n\n#[derive(Debug, Error)]\npub enum WritingError {\n    #[error(\"IO error: {0}\")]","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/Pumpkin-MC/Pumpkin/blob/8d4639e25a57c15e47448ec327c780d41bbf2356/crates/pumpkin-protocol/src/ser/mod.rs#L3-L39","documentation":"ReadingError::CleanEOF is produced by the protocol's async reader when it attempts to read a field of the given size but the stream has ended with no bytes left to consume. It is the serde-style deserializer's way of reporting a clean end-of-stream: the peer closed the connection mid-decode expectation, with zero bytes available for the requested read.","triggerScenarios":"Calling any read/deserialize step (e.g. reading a VarInt, length prefix, or fixed-size buffer) on a TcpStream whose peer has closed; the reader tries to fill the requested byte count from an exhausted reader.","commonSituations":"A Minecraft client disconnecting right as the server awaits the next packet; a keep-alive/poll loop reading a closed socket; reading from a half-closed connection after a client crash or timeout on the peer side.","solutions":["Treat CleanEOF at packet boundaries as a normal disconnect: log at debug level and close the connection gracefully.","Check for stream closure (read returning Ok(0)) before attempting to decode the next packet.","Do not retry reads on a closed stream; re-establish the connection if communication must continue.","If it happens mid-packet rather than at a boundary, check whether the sender truncates packets (see Incomplete)."],"exampleFix":"// before: logging every EOF as an error and spamming logs\nerror!(\"read failed: {e}\");\n\n// after: distinguish clean disconnects\nmatch e {\n    ReadingError::CleanEOF(_) => debug!(\"client disconnected\"),\n    other => error!(\"read failed: {other}\"),\n}","handlingStrategy":"try-catch","validationCode":"// check stream liveness before a read loop iteration\nif stream.peek(&mut [0u8; 1]).await?.is_empty() { break; } // peer closed","typeGuard":null,"tryCatchPattern":"match reader.next_packet().await {\n    Err(ReadingError::CleanEOF(_)) => {\n        debug!(\"peer closed connection cleanly\");\n        break; // normal disconnect path\n    }\n    Err(e) => warn!(\"read error: {e}\"),\n    Ok(p) => handle(p),\n}","preventionTips":["Treat end-of-stream as an expected event in connection loops, not an error.","Enable TCP keepalive to detect dead peers faster.","Never reuse a reader after a CleanEOF; recreate the connection if needed."],"tags":["rust","network","eof","tcp","protocol"],"backgroundTag":"unexpected-response-shape","analyzedSha":"8d4639e25a57c15e47448ec327c780d41bbf2356","analyzedAt":"2026-09-09T15:32:22.916Z","contentChangedAt":"2026-09-09T15:32:22.916Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}