aio-libs/aiohttp · error · ContentLengthError
Not enough data to satisfy content length header
Error message
Not enough data to satisfy content length header (received {received} of {self._length_expected} bytes). What it means
Raised as ContentLengthError (a BadHttpMessage subclass) when the connection reaches EOF but fewer body bytes were received than declared by Content-Length. HttpPayloadParser.feed_eof, in the PARSE_LENGTH branch, checks if self._length is still positive (bytes still owed); if so it raises with the received vs expected counts. This indicates a truncated message body.
Solutions
- If you are the sender, ensure you write exactly Content-Length body bytes before closing.
- On the receiving side, treat this as a connection-level error and retry the request idempotently.
- Verify no intermediary (proxy, firewall) is truncating large responses.
- If the body length is genuinely unknown, use chunked transfer-encoding instead of Content-Length.
- Check server logs for exceptions during response streaming.
Example fix
# before (server computes Content-Length wrong)
return web.Response(body=data, headers={'Content-Length': str(len(data) + 10)})
# after (let aiohttp set Content-Length, or use chunked)
return web.Response(body=data) # Content-Length auto-set correctly Defensive patterns
Strategy: retry
Validate before calling
async def safe_read(resp) -> bytes:
try:
return await resp.read()
except Exception:
# ContentLengthError indicates truncation; caller decides on retry
raise Try / catch
from aiohttp.http_exceptions import ContentLengthError
import aiohttp
async def fetch_full(url, *, attempts=3):
last = None
for i in range(attempts):
try:
async with aiohttp.ClientSession() as s:
async with s.get(url) as r:
return await r.read()
except ContentLengthError as e:
last = e
await asyncio.sleep(2 ** i)
raise last
Prevention
- Retry idempotent requests on truncation errors.
- Verify servers compute Content-Length correctly (or omit it / use chunked).
- Check intermediaries for response truncation on large payloads.
- Use chunked encoding when body length is uncertain.
When it happens
Trigger: A response/request has a Content-Length: N header, but the stream closes (feed_eof) before N body bytes arrive. Fires when _type == ParseState.PARSE_LENGTH and self._length > 0 at EOF.
Common situations: The server (or client) closes the connection mid-body before sending all Content-Length bytes; a proxy truncating the response; network resets/instability dropping the tail; a server that sets Content-Length but then errors out sending fewer bytes; chunked encoding incorrectly absent; a buggy upstream that miscomputes Content-Length.
Related errors
- Not enough data to satisfy transfer length header.
- Content length is set automatically
- body and text are not allowed together
- Can not serialize value type: %r headers: %r value: %r
- Cannot clone request after reading its content
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/118473f5c82745c0.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/http_parser.py:921
def pause_reading(self) -> None:
self._paused = True
def feed_eof(self) -> None:
if self._type == ParseState.PARSE_UNTIL_EOF:
self._eof_pending = True
while self._more_data_available:
if self._paused:
self._paused = False
return # Will resume via feed_data(b"") later
self._more_data_available = self.payload.feed_data(b"")
self.payload.feed_eof()
self.done = True
self._eof_pending = False
elif self._type == ParseState.PARSE_LENGTH:
if self._length:
received = self._length_expected - self._length
raise ContentLengthError(
f"Not enough data to satisfy content length header "
f"(received {received} of {self._length_expected} bytes)."
)
# Body has already been received, but parser paused.
while self._more_data_available:
if self._paused:
self._paused = False
return # Will resume via feed_data(b"") later
self._more_data_available = self.payload.feed_data(b"")
self.payload.feed_eof()
self.done = True
elif self._type == ParseState.PARSE_CHUNKED:
raise TransferEncodingError(
"Not enough data to satisfy transfer length header."
)
def feed_data(
self, chunk: bytes, SEP: _SEP = b"\r\n", CHUNK_EXT: bytes = b";"View on GitHub (pinned to d041d4d0fd)