{"record":{"id":"acf09cb8bd72311b","repo":"affaan-m/ECC","slug":"unexpected-eof-while-reading-http-request-body","errorCode":null,"errorMessage":"Unexpected EOF while reading HTTP request body","messagePattern":"Unexpected EOF while reading HTTP request body","errorType":"http","errorClass":"anyhow::Error","httpStatus":400,"severity":"warning","filePath":"ecc2/src/main.rs","lineNumber":4244,"sourceCode":"    let mut headers = BTreeMap::new();\n    for line in lines {\n        if line.is_empty() {\n            break;\n        }\n        if let Some((key, value)) = line.split_once(':') {\n            headers.insert(key.trim().to_ascii_lowercase(), value.trim().to_string());\n        }\n    }\n\n    let content_length = headers\n        .get(\"content-length\")\n        .and_then(|value| value.parse::<usize>().ok())\n        .unwrap_or(0);\n    let mut body = buffer[header_end..].to_vec();\n    while body.len() < content_length {\n        let read = stream.read(&mut temp)?;\n        if read == 0 {\n            anyhow::bail!(\"Unexpected EOF while reading HTTP request body\");\n        }\n        body.extend_from_slice(&temp[..read]);\n    }\n    body.truncate(content_length);\n\n    Ok((method, path, headers, body))\n}\n\nfn write_http_response(\n    stream: &mut TcpStream,\n    status: u16,\n    content_type: &str,\n    body: &str,\n) -> Result<()> {\n    let status_text = match status {\n        200 => \"OK\",\n        202 => \"Accepted\",\n        400 => \"Bad Request\",","sourceCodeStart":4226,"sourceCodeEnd":4262,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/ecc2/src/main.rs#L4226-L4262","documentation":"After parsing headers, the reader continues pulling from the socket until the body reaches the `Content-Length` byte count. If the stream returns 0 (client disconnected) before the body is complete, it bails with this error. It distinguishes truncated request bodies from header-phase EOFs.","triggerScenarios":"A client sends a `Content-Length: N` header but closes the connection after transmitting fewer than N body bytes — aborted uploads, dropped connections mid-POST, or a client that lied about content length.","commonSituations":"User cancels a large POST/upload halfway; flaky network drops the TCP connection during a request body transfer; a hand-rolled HTTP client that sets `Content-Length` incorrectly; a proxy timing out and severing the upstream connection.","solutions":["Retry the request from the client.","Ensure the client's declared `Content-Length` exactly matches the bytes it writes.","Check network/proxy stability for large request bodies; consider `Transfer-Encoding: chunked` via a full HTTP client instead of raw sockets.","If your client is hand-written, flush the entire body before closing the stream."],"exampleFix":"// before (client)\nwrite!(s, \"Content-Length: 100\\r\\n\\r\\n\")?;\ns.write_all(short_body)?; // fewer than 100 bytes\n\n// after\nwrite!(s, \"Content-Length: {}\\r\\n\\r\\n\", body.len())?;\ns.write_all(&body)?;","handlingStrategy":"retry","validationCode":"// Client: ensure Content-Length matches the body exactly\nassert_eq!(body.len(), declared_content_length);","typeGuard":null,"tryCatchPattern":"match send_request_with_body(req, body) {\n    Err(e) if e.to_string().contains(\"Unexpected EOF\") => {\n        // transient drop: retry with backoff\n        retry_with_backoff(3, || send_request_with_body(req, body))\n    }\n    other => other,\n}","preventionTips":["Always compute Content-Length from the actual body bytes.","Use a full HTTP client (reqwest/ureq) instead of raw sockets to avoid framing mistakes.","Avoid sending very large bodies over unstable links; chunk or compress."],"tags":["http","network","rust"],"backgroundTag":"broken-pipe","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}