aio-libs/aiohttp · error · ValueError
invalid Content-Length: {length!r}
Error message
invalid Content-Length: {length!r} What it means
ValueError raised by BodyPartReader.__init__ when a (non-form-data) multipart body part's Content-Length is present but not purely ASCII digits. aiohttp rejects signs, whitespace, underscores, and non-ASCII digits that int() would otherwise accept, per RFC 9110 section 8.6.
Source
Thrown at aiohttp/multipart.py:304
default_charset: str | None = None,
max_decompress_size: int = DEFAULT_CHUNK_SIZE,
client_max_size: int = sys.maxsize,
max_size_error_cls: type[Exception] = ValueError,
) -> None:
self.headers = headers
self._boundary = boundary
self._boundary_len = len(boundary) + 2 # Boundary + \r\n
self._content = content
self._default_charset = default_charset
self._at_eof = False
self._is_form_data = subtype == "form-data"
# https://datatracker.ietf.org/doc/html/rfc7578#section-4.8
length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None)
if length is not None and not (length.isascii() and length.isdigit()):
# Reject sign prefixes, underscores, whitespace and non-ASCII
# digits that int() would otherwise accept.
# https://www.rfc-editor.org/rfc/rfc9110#section-8.6
raise ValueError(f"invalid Content-Length: {length!r}")
self._length = int(length) if length is not None else None
self._read_bytes = 0
self._unread: deque[bytes] = deque()
self._prev_chunk: bytes | None = None
self._content_eof = 0
self._cache: dict[str, Any] = {}
self._max_decompress_size = max_decompress_size
self._client_max_size = client_max_size
self._max_size_error_cls = max_size_error_cls
def __aiter__(self) -> Self:
return self
async def __anext__(self) -> bytes:
part = await self.next()
if part is None:
raise StopAsyncIteration
return partView on GitHub (pinned to c0ef574e29)
Solutions
- Validate the multipart payload source (browser/encoder) sets a plain-digit Content-Length.
- Sanitise/normalise part Content-Length before constructing BodyPartReader if you control framing.
- Catch ValueError when iterating parts and return 400.
Defensive patterns
Strategy: validation
Validate before calling
def valid_part_length(length: str | None) -> bool:
return length is None or (length.isascii() and length.isdigit()) Type guard
def valid_part_length(length: str | None) -> bool:
return length is None or (length.isascii() and length.isdigit()) Try / catch
try:
async for part in multipart_reader:
...
except ValueError:
return web.Response(status=400, text='invalid part Content-Length') Prevention
- Ensure multipart part Content-Length is plain digits.
- Validate uploaded multipart at the edge.
When it happens
Trigger: Reading a multipart payload where a part carries a Content-Length like '+10', '1_000', ' 10 ', or non-ASCII digits. The constructor checks `length.isascii() and length.isdigit()` and raises ValueError before parsing.
Common situations: Malformed multipart payloads from a buggy uploader; crafted input probing int() leniency; a part header injected with whitespace/sign; custom client setting Content-Length incorrectly.
Related errors
- filename must be an instance of str. Got: %s
- content_type must be an instance of str. Got: %s
- {path}
- Missing 'Host' header in request.
- Not enough data to satisfy content length header (received {
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/e625148e4230eed6.json.
Report an issue: GitHub.