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

Invalid chunk end LF

Error message

Invalid chunk end LF

What it means

Raised in read_end_lf (chunked.rs:181) when, after the CR of the trailer terminator, the next byte is not '\n'. It is the final check of the chunked state machine (transitioning to ChunkedState::End); a missing LF means the body terminator is malformed and the stream is rejected as PayloadError::Io.

Solutions

  1. Ensure the body ends with the complete "0\r\n\r\n" sequence.
  2. Use a compliant HTTP client library for chunked uploads.
  3. Verify proxies forward the complete terminator without truncation.

Example fix

// before
"0\r\n\r"
// 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 LF after last chunk CR
    _ => { /* ... */ }
}

Prevention

When it happens

Trigger: The end sequence is "0\r\n\r" but the final '\n' is missing or replaced - e.g. the connection closes after a lone CR, or a non-LF byte follows.

Common situations: Truncated final chunk terminator; proxy stripping the last LF; client bug; connection drop mid-terminator.

Related errors


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

Appendix: source

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

            _ => 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 {
    use actix_codec::Decoder as _;
    use bytes::{Bytes, BytesMut};
    use http::Method;

    use crate::{
        error::ParseError,
        h1::decoder::{MessageDecoder, PayloadItem},
        HttpMessage as _, Request,
    };

View on GitHub (pinned to 4d435abc28)