actix/actix-web · error · io::Error

Invalid chunk end CR

Error message

Invalid chunk end CR

What it means

Raised in read_end_cr (chunked.rs:172) when the byte following the terminating zero-size chunk's CRLF is not CR. A zero-length chunk ("0\r\n") signals the end of the chunked body; it must itself be followed by CRLF (the trailer block terminator). This state expects that leading CR.

Solutions

  1. Always send the terminating sequence "0\r\n\r\n" (last-chunk + empty trailer line).
  2. If sending trailers, ensure each trailer line ends with CRLF and the block is terminated by a final CRLF.
  3. Use a standard HTTP client to avoid hand-rolling the terminator.

Example fix

// before
"0\r\n"  // missing final CRLF
// after
"0\r\n\r\n"
Defensive patterns

Strategy: try-catch

Try / catch

match payload.next().await {
    Some(Err(PayloadError::Io(e))) if e.kind() == io::ErrorKind::InvalidInput =>
        return HttpResponse::BadRequest().finish(), // missing CR after last chunk
    _ => { /* ... */ }
}

Prevention

When it happens

Trigger: After the final "0\r\n", the next byte is not CR - e.g. the stream omits the trailing CRLF or sends data where the trailer-terminating CRLF should be. read_size_lf routes a size==0 chunk to EndCr expecting '\r'.

Common situations: Client omitting the final CRLF after the last-chunk; truncated upload; proxy that drops the trailer terminator; malformed trailer section.

Related errors


AI-assisted analysis of actix/actix-web@4d435abc28 (2026-08-09). Data as JSON: /api/errors/ec4ac6a50c92c701. Report an issue: GitHub.

Appendix: source

Thrown at actix-http/src/h1/chunked.rs:172

            _ => Poll::Ready(Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Invalid chunk body CR",
            ))),
        }
    }
    fn read_body_lf(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {
        match byte!(rdr) {
            b'\n' => Poll::Ready(Ok(ChunkedState::Size)),
            _ => Poll::Ready(Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Invalid chunk body LF",
            ))),
        }
    }
    fn read_end_cr(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {
        match byte!(rdr) {
            b'\r' => Poll::Ready(Ok(ChunkedState::EndLf)),
            _ => Poll::Ready(Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Invalid chunk end CR",
            ))),
        }
    }
    fn read_end_lf(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {
        match byte!(rdr) {
            b'\n' => Poll::Ready(Ok(ChunkedState::End)),
            _ => Poll::Ready(Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Invalid chunk end LF",
            ))),
        }
    }
}

#[cfg(test)]
mod tests {

View on GitHub (pinned to 4d435abc28)