{"id":"f94a7ecf775e57ed","repo":"hyperium/hyper","slug":"read-header-from-client-timeout","errorCode":null,"errorMessage":"read header from client timeout","messagePattern":"read header from client timeout","errorType":"exception","errorClass":"hyper::Error","httpStatus":null,"severity":"warning","filePath":"src/error.rs","lineNumber":437,"sourceCode":"        feature = \"ffi\"\n    ))]\n    pub(super) fn new_body_write_aborted() -> Error {\n        Error::new(Kind::User(User::BodyWriteAborted))\n    }\n\n    fn new_user(user: User) -> Error {\n        Error::new(Kind::User(user))\n    }\n\n    #[cfg(any(feature = \"http1\", feature = \"http2\"))]\n    #[cfg(feature = \"server\")]\n    pub(super) fn new_user_header() -> Error {\n        Error::new_user(User::UnexpectedHeader)\n    }\n\n    #[cfg(all(feature = \"http1\", feature = \"server\"))]\n    pub(super) fn new_header_timeout() -> Error {\n        Error::new(Kind::HeaderTimeout)\n    }\n\n    #[cfg(feature = \"http1\")]\n    #[cfg(feature = \"server\")]\n    pub(super) fn new_user_unsupported_status_code() -> Error {\n        Error::new_user(User::UnsupportedStatusCode)\n    }\n\n    pub(super) fn new_user_no_upgrade() -> Error {\n        Error::new_user(User::NoUpgrade)\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_user_manual_upgrade() -> Error {\n        Error::new_user(User::ManualUpgrade)\n    }\n\n    #[cfg(any(","sourceCodeStart":419,"sourceCodeEnd":455,"githubUrl":"https://github.com/hyperium/hyper/blob/084473f728f9d07b3be5845475aa2f62ed9ff579/src/error.rs#L419-L455","documentation":"Thrown via Error::new_header_timeout() (src/error.rs:437, Kind::HeaderTimeout), HTTP/1 server only. It fires when the client does not send the full request head (request line + headers) within header_read_timeout — the timer (which requires a Timer set via Builder::timer) elapses while hyper is still Pending on the head parse (proto/h1/conn.rs:264). The default is 30s (server/conn/http1.rs:250). Detect with Error::is_timeout().","triggerScenarios":"A client opens a TCP/TLS connection but never sends (or only slowly sends) the request line+headers; a port scanner / health check that opens a socket and idles; slowloris-style attack. The header timer at conn.rs:219-234 fires and poll_read_head returns Err(new_header_timeout()) at conn.rs:264.","commonSituations":"Forgotten to call Builder::timer (the timeout is a no-op without a Timer, and configuring it without a timer panics — see server/conn/http1.rs:346/480); load balancer health checks that hold connections open; misbehaving or malicious slow clients; default 30s too short for very slow uploaders.","solutions":["Ensure a Timer is installed (Builder::timer with tokio time) so the timeout actually takes effect, and pick a sane header_read_timeout for your clients.","If legitimate slow clients trip it, raise header_read_timeout (or disable it) — but keep some limit to resist slowloris.","Put a connection-level idle/read timeout in front (reverse proxy) as defense in depth."],"exampleFix":"// before: header_read_timeout configured but no Timer => panic, or no effect\nlet mut http = Http::new();\nhttp.header_read_timeout(std::time::Duration::from_secs(30));\n\n// after: install the tokio Timer so the timeout is enforced\nlet mut http = Http::new();\nhttp.with_upgrades();\nhttp.timer(tokio_compat::Timer::new());\nhttp.header_read_timeout(std::time::Duration::from_secs(30));","handlingStrategy":"try-catch","validationCode":"// Confirm a Timer is installed before the server runs, otherwise the\n// timeout silently does nothing (or panics if set without a Timer).\nfn assert_timer_configured(b: &hyper::server::conn::http1::Builder) {\n    // Builder::timer must have been called for header_read_timeout to take effect\n    let _ = b; // your framework wrapper should expose/require the timer\n}","typeGuard":"fn is_header_timeout(err: &hyper::Error) -> bool {\n    err.is_timeout()\n}","tryCatchPattern":"if let Err(e) = conn_fut.await {\n    if e.is_timeout() {\n        // client was too slow sending headers; just close\n    } else {\n        tracing::error!(\"conn error: {e}\");\n    }\n}","preventionTips":["Always call Builder::timer(...) when you set header_read_timeout, or it panics/no-ops.","Pick a header_read_timeout that tolerates your slowest legitimate client.","Layer a reverse-proxy idle timeout as defense-in-depth against slowloris."],"tags":["http1","server","timeout","slowloris","rust"],"analyzedSha":"084473f728f9d07b3be5845475aa2f62ed9ff579","analyzedAt":"2026-08-06T01:20:18.522Z","schemaVersion":2}