hyperium/hyper · error · std::io::Error

chunk trailers count overflow

Error message

chunk trailers count overflow

What it means

Thrown in read_trailer_lf (src/proto/h1/decode.rs:563) when the count of trailer fields parsed after the final zero-length chunk reaches the configured h1_max_headers limit (default DEFAULT_MAX_HEADERS from the role module; configurable via hyper's h1_max_headers builder option). Each completed trailer line (CRLF) increments trailers_cnt, and exceeding the cap raises io::ErrorKind::InvalidData to bound memory use.

Source

Thrown at src/proto/h1/decode.rs:563

        match byte {
            b'\r' => Poll::Ready(Ok(ChunkedState::TrailerLf)),
            _ => Poll::Ready(Ok(ChunkedState::Trailer)),
        }
    }

    fn read_trailer_lf<R: MemRead>(
        cx: &mut Context<'_>,
        rdr: &mut R,
        trailers_buf: &mut Option<BytesMut>,
        trailers_cnt: &mut usize,
        h1_max_headers: usize,
        h1_max_header_size: usize,
    ) -> Poll<Result<ChunkedState, io::Error>> {
        let byte = byte!(rdr, cx);
        match byte {
            b'\n' => {
                if *trailers_cnt >= h1_max_headers {
                    return Poll::Ready(Err(io::Error::new(
                        io::ErrorKind::InvalidData,
                        "chunk trailers count overflow",
                    )));
                }
                *trailers_cnt += 1;

                put_u8!(
                    trailers_buf.as_mut().expect("trailers_buf is None"),
                    byte,
                    h1_max_header_size
                );

                Poll::Ready(Ok(ChunkedState::EndCr))
            }
            _ => Poll::Ready(Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Invalid trailer end LF",
            ))),

View on GitHub (pinned to 084473f728)

Solutions

  1. Raise the cap via hyper's builder if legitimate: Builder::http1_max_headers(N) (server) / http1_max_headers on the client builder when available.
  2. Reduce the number of trailers the sender emits (aggregate metadata into fewer headers).
  3. If the trailers are unexpected, investigate why the peer is sending them (proxy injecting headers after the body).

Example fix

// before: default trailer header cap
let server = hyper::server::Server::bind(&addr).serve(make_svc);

// after: raise the h1 max-headers cap
let server = hyper::server::Server::bind(&addr)
    .http1_max_headers(200)
    .serve(make_svc);
Defensive patterns

Strategy: validation

Validate before calling

// Configure the trailer-count cap to match what your peers legitimately send.
let server = hyper::server::Server::bind(&addr)
    .http1_max_headers(expected_trailer_count + slack);
let client = hyper::Client::builder()
    .http1_max_headers(expected_trailer_count + slack)
    .build_http::<hyper::Body>();

Try / catch

Some(Err(e)) => {
    if e.to_string().contains("chunk trailers count overflow") {
        metrics::increment!("hyper.trailers.count_overflow");
        tracing::warn!(error=%e, "too many trailers; raising h1_max_headers may be needed");
        break;
    }
    return Err(e.into());
}

Prevention

When it happens

Trigger: A chunked body terminating with "0\r\n" followed by more trailer headers than h1_max_headers allows — e.g. a gRPC-style response that attaches dozens of metadata trailers when the server caps trailers at the default.

Common situations: Distributed-tracing or gRPC proxies that forward many metadata headers as trailers; raising security limits elsewhere while forgetting the trailer count cap; a malicious client flooding trailers.

Related errors


AI-assisted analysis of hyperium/hyper@084473f728 (2026-08-06). Data as JSON: /data/errors/763d512ae913e531.json. Report an issue: GitHub.