hyperium/hyper · error · std::io::Error
Partial header
Error message
Partial header
What it means
Thrown by decode_trailers (src/proto/h1/decode.rs:672) when httparse::parse_headers returns Status::Partial on the buffered trailer block — meaning the accumulated bytes do not form a complete, properly-terminated set of headers (no final blank-line CRLF that the parser accepts as Complete). Reported as io::ErrorKind::InvalidInput.
Source
Thrown at src/proto/h1/decode.rs:672
}
};
let value = match HeaderValue::from_bytes(header.value) {
Ok(value) => value,
Err(_) => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("Invalid header value: {:?}", &header),
));
}
};
trailers.append(name, value);
}
Ok(trailers)
}
Ok(httparse::Status::Partial) => Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Partial header",
)),
Err(e) => Err(io::Error::new(io::ErrorKind::InvalidInput, e)),
}
}
#[derive(Debug)]
struct IncompleteBody;
impl fmt::Display for IncompleteBody {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "end of file before message length reached")
}
}
impl StdError for IncompleteBody {}
View on GitHub (pinned to 084473f728)
Solutions
- Raise h1_max_header_size via the builder if a legitimate trailer is larger than the 16 KiB default.
- Confirm the sender writes the trailer-terminating blank line ("\r\n") after the last trailer.
- Split oversized trailer values or move them into the body.
- Capture the trailer bytes and run httparse on them locally to see exactly where parsing goes partial.
Example fix
// before: default 16 KiB trailer cap, oversized trailer truncated
let srv = Server::bind(&addr).serve(make_svc);
// after: raise trailer byte limit
let srv = Server::bind(&addr)
.http1_max_header_size(1024 * 64)
.serve(make_svc); Defensive patterns
Strategy: validation
Validate before calling
// Size trailer budgets to fit within h1_max_header_size (default 16 KiB).
let max_header_size = 1024 * 64; // raise the cap to fit legitimate trailers
let server = hyper::server::Server::bind(&addr)
.http1_max_header_size(max_header_size)
.serve(make_svc);
// On send: ensure each trailer line + the final blank line fit the cap.
assert!(trailer_block.len() < max_header_size); Try / catch
Some(Err(e)) => {
if e.to_string().contains("Partial header") {
tracing::warn!(error=%e, "trailer block parsed as partial; check h1_max_header_size / terminator");
break;
}
return Err(e.into());
} Prevention
- Set h1_max_header_size above the largest legitimate trailer line on both server and client.
- Always terminate the trailer block with a blank CRLF line.
- If a trailer is huge, move the payload into the body.
When it happens
Trigger: A trailer block that is internally cut off or mis-sequenced so httparse sees it as partial — e.g. trailers that reached the byte-size cap (TRAILER_LIMIT / h1_max_header_size) mid-header, or framing where the terminating blank line is malformed. The state machine reached End but the bytes collected in trailers_buf don't parse cleanly.
Common situations: A trailer that exceeds the trailer byte cap (h1_max_header_size, default 16 KiB) causing the buffer to be cut mid-header; a peer that emits trailers without the final blank line; interference from a proxy that rewrites the trailer section.
Related errors
- chunk trailers count overflow
- Invalid header name: {:?}
- Invalid header value: {:?}
- chunk extensions over limit
- Invalid trailer end LF
AI-assisted analysis of hyperium/hyper@084473f728 (2026-08-06).
Data as JSON: /data/errors/bce2229c42f114a1.json.
Report an issue: GitHub.