{"record":{"id":"39bbb835ca3249e8","repo":"tokio-rs/tokio","slug":"early-eof","errorCode":null,"errorMessage":"early eof","messagePattern":"early eof","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"tokio-util/src/io/read_arc.rs","lineNumber":36,"sourceCode":"///\n/// let arc = read_exact_arc(read, 4).await?;\n///\n/// assert_eq!(&arc[..], &[42; 4]);\n/// # Ok(())\n/// # }\n/// ```\npub async fn read_exact_arc<R: AsyncRead>(read: R, len: usize) -> io::Result<Arc<[u8]>> {\n    tokio::pin!(read);\n    // TODO(MSRV 1.82): When bumping MSRV, switch to `Arc::new_uninit_slice(len)`. The following is\n    // equivalent, and generates the same assembly, but works without requiring MSRV 1.82.\n    let arc: Arc<[MaybeUninit<u8>]> = (0..len).map(|_| MaybeUninit::uninit()).collect();\n    // TODO(MSRV future): Use `Arc::get_mut_unchecked` once it's stabilized.\n    // SAFETY: We're the only owner of the `Arc`, and we keep the `Arc` valid throughout this loop\n    // as we write through this reference.\n    let mut buf = unsafe { &mut *(Arc::as_ptr(&arc) as *mut [MaybeUninit<u8>]) };\n    while !buf.is_empty() {\n        if read.read_buf(&mut buf).await? == 0 {\n            return Err(io::Error::new(io::ErrorKind::UnexpectedEof, \"early eof\"));\n        }\n    }\n    // TODO(MSRV 1.82): When bumping MSRV, switch to `arc.assume_init()`. The following is\n    // equivalent, and generates the same assembly, but works without requiring MSRV 1.82.\n    // SAFETY: This changes `[MaybeUninit<u8>]` to `[u8]`, and we've initialized all the bytes in\n    // the loop above.\n    Ok(unsafe { Arc::from_raw(Arc::into_raw(arc) as *const [u8]) })\n}\n","sourceCodeStart":18,"sourceCodeEnd":45,"githubUrl":"https://github.com/tokio-rs/tokio/blob/625954f365727668cb02d04172b34f1149637728/tokio-util/src/io/read_arc.rs#L18-L45","documentation":"Runtime error from `read_exact_arc` (read_arc.rs:36). Like `AsyncReadExt::read_exact`, it must fill exactly `len` bytes; if the reader returns `0` (EOF) before that, it returns `io::ErrorKind::UnexpectedEof` and discards the partial buffer.","triggerScenarios":"Requesting `read_exact_arc(r, len)` when the source yields fewer than `len` bytes then EOF: a truncated length-prefixed payload, a short file, or an overestimated `len`.","commonSituations":"Peer sent fewer bytes than the length prefix implied; file shorter than expected; passing a too-large `len`; header advertised a body size that never fully arrived.","solutions":["Verify the requested `len` matches the actual available data / protocol-advertised length.","Handle `UnexpectedEof` as a truncated-message protocol error (close/reconnect).","Use `read_buf`/variable-length reading if the exact length is not guaranteed.","Validate the length prefix against a sane maximum before issuing the exact read."],"exampleFix":"// before: assuming the full payload arrives\nlet payload = read_exact_arc(stream, header.len as usize).await?;\n\n// after: treat a short stream as a protocol error\nlet payload = read_exact_arc(stream, header.len as usize)\n    .await\n    .map_err(|e| match e.kind() {\n        io::ErrorKind::UnexpectedEof => proto_err(\"truncated payload\"),\n        _ => e.into(),\n    })?;","handlingStrategy":"try-catch","validationCode":"// Validate the length prefix before the exact read\nif header.len as usize > MAX_PAYLOAD { return Err(proto_err(\"length exceeds cap\")); }\nlet n = header.len as usize;","typeGuard":"fn is_early_eof(e: &io::Error) -> bool { e.kind() == io::ErrorKind::UnexpectedEof }","tryCatchPattern":"let payload = read_exact_arc(stream, n).await.map_err(|e| {\n    if is_early_eof(&e) { proto_err(\"truncated payload\") } else { e.into() }\n})?;","preventionTips":["Validate the length prefix against a sane maximum before requesting an exact read.","Treat `UnexpectedEof` as a protocol/truncation error, not a transient retry.","Use variable-length reads when the size is not guaranteed."],"tags":["rust","tokio","tokio-util","io","eof","async-read","runtime"],"backgroundTag":null,"analyzedSha":"625954f365727668cb02d04172b34f1149637728","analyzedAt":"2026-08-11T17:46:45.378Z","contentChangedAt":"2026-08-11T17:46:45.378Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}