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

Invalid chunk size linear white space

Error message

Invalid chunk size linear white space

What it means

Raised in read_size_lws (chunked.rs:95) when, after consuming linear whitespace (space/tab) following the chunk size, the next byte is not another LWS, a ';' (extension), or CR. RFC 7230 allows optional LWS after the size but nothing else, so any other character is a framing error surfacing as PayloadError::Io / 400.

Solutions

  1. Ensure chunk-size lines are strictly <hex-size> [ ";ext" ] CRLF with only optional spaces/tabs before the extension or CRLF.
  2. Use a mature HTTP client library rather than hand-serializing chunked bodies.
  3. Verify any intermediary proxy preserves chunk framing byte-for-byte.

Example fix

// before
"4 x\r\ndata\r\n"
// after
"4\r\ndata\r\n"  // or "4;ext\r\ndata\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(), // bad LWS after chunk size
    _ => { /* ... */ }
}

Prevention

When it happens

Trigger: A chunk-size line like "4 X\r\n" where a non-LWS character follows the whitespace, or stray bytes after the size digits. The SizeLws state only accepts \t, ' ', ';', '\r'.

Common situations: Client inserting stray characters after the chunk size; corrupt body from a proxy; malformed custom HTTP serializer.

Related errors


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

Appendix: source

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

                Poll::Ready(Ok(ChunkedState::Size))
            }
            None => {
                debug!("chunk size would overflow u64");
                Poll::Ready(Err(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    "Invalid chunk size line: Size is too big",
                )))
            }
        }
    }

    fn read_size_lws(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {
        match byte!(rdr) {
            // LWS can follow the chunk size, but no more digits can come
            b'\t' | b' ' => Poll::Ready(Ok(ChunkedState::SizeLws)),
            b';' => Poll::Ready(Ok(ChunkedState::Extension)),
            b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
            _ => Poll::Ready(Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Invalid chunk size linear white space",
            ))),
        }
    }
    fn read_extension(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {
        match byte!(rdr) {
            b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
            // strictly 0x20 (space) should be disallowed but we don't parse quoted strings here
            0x00..=0x08 | 0x0a..=0x1f | 0x7f => Poll::Ready(Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Invalid character in chunk extension",
            ))),
            _ => Poll::Ready(Ok(ChunkedState::Extension)), // no supported extensions
        }
    }
    fn read_size_lf(rdr: &mut BytesMut, size: u64) -> Poll<Result<ChunkedState, io::Error>> {
        match byte!(rdr) {

View on GitHub (pinned to 4d435abc28)