aio-libs/aiohttp · error · ValueError
Invalid Content-Length header: {content_length_hdr!r}
Error message
Invalid Content-Length header: {content_length_hdr!r} What it means
Raised as ValueError in ClientRequest._get_content_length() when a Content-Length header is present but its value is not all ASCII digits (fails _DIGITS_RE.fullmatch). HTTP forbids non-digit Content-Length values; this guard catches malformed or tampered header values before the request is sent.
Source
Thrown at aiohttp/client_reqrep.py:864
self.headers[hdrs.AUTHORIZATION] = encode_basic_auth(
url.user or "", url.password or ""
)
def _reset_writer(self, _: object = None) -> None:
self._writer_task = None
def _get_content_length(self) -> int | None:
"""Extract and validate Content-Length header value.
Returns parsed Content-Length value or None if not set.
Raises ValueError if header exists but cannot be parsed as an integer.
"""
if hdrs.CONTENT_LENGTH not in self.headers:
return None
content_length_hdr = self.headers[hdrs.CONTENT_LENGTH]
if not _DIGITS_RE.fullmatch(content_length_hdr):
raise ValueError(f"Invalid Content-Length header: {content_length_hdr!r}")
return int(content_length_hdr)
@property
def _writer(self) -> asyncio.Task[None] | None:
return self._writer_task
@_writer.setter
def _writer(self, writer: asyncio.Task[None]) -> None:
if self._writer_task is not None:
self._writer_task.remove_done_callback(self._reset_writer)
self._writer_task = writer
writer.add_done_callback(self._reset_writer)
def is_ssl(self) -> bool:
return self.url.scheme in _SSL_SCHEMES
@property
def ssl(self) -> "SSLContext | bool | Fingerprint":View on GitHub (pinned to c0ef574e29)
Solutions
- Let aiohttp compute Content-Length automatically from the body instead of setting it manually.
- If you must set it, ensure the value is a clean decimal integer string.
- Strip whitespace and remove duplicate headers before assignment.
- When forwarding headers, collapse duplicates instead of concatenating with commas.
Example fix
# before headers['Content-Length'] = str(len(body)) + ' ' # trailing space headers['Content-Length'] = '0x10' # after # (preferred) omit Content-Length; aiohttp sets it from the body # or headers['Content-Length'] = str(int(len(body)))
Defensive patterns
Strategy: validation
Validate before calling
import re
if 'Content-Length' in headers:
val = headers['Content-Length']
assert re.fullmatch(r'\d+', val), f'bad Content-Length {val!r}' Type guard
def is_valid_content_length(value: str) -> bool:
import re
return bool(re.fullmatch(r'\d+', str(value))) Prevention
- Let aiohttp compute Content-Length from the body whenever possible.
- Never concatenate duplicate Content-Length headers.
- Validate header values copied from upstream responses.
When it happens
Trigger: Fires at line 862-864 when self.headers[CONTENT_LENGTH] is something like '10 ', '0x10', '1, 1' (comma from proxy chains), or ''. Most often triggered by manually set headers or headers injected by middleware.
Common situations: Manually setting Content-Length to a non-numeric value; duplicate Content-Length headers collapsing to '1, 1'; trailing whitespace from string concatenation; copying headers from another response verbatim.
Related errors
- Method cannot contain non-token characters {method!r} (found
- Duplicate '{name}' header found.
- Transfer-Encoding can't be present with Content-Length
- Missing 'Host' header in request.
- compress can not be set if Content-Encoding header is set
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/f8f21d513ceece10.json.
Report an issue: GitHub.