{"record":{"id":"24859c8172b3e955","repo":"aio-libs/aiohttp","slug":"not-enough-data-to-satisfy-transfer-length-header","errorCode":null,"errorMessage":"Not enough data to satisfy transfer length header.","messagePattern":"Not enough data to satisfy transfer length header\\.","errorType":"http","errorClass":"TransferEncodingError","httpStatus":400,"severity":"error","filePath":"aiohttp/http_parser.py","lineNumber":934,"sourceCode":"            self.done = True\n            self._eof_pending = False\n        elif self._type == ParseState.PARSE_LENGTH:\n            if self._length:\n                received = self._length_expected - self._length\n                raise ContentLengthError(\n                    f\"Not enough data to satisfy content length header \"\n                    f\"(received {received} of {self._length_expected} bytes).\"\n                )\n            # Body has already been received, but parser paused.\n            while self._more_data_available:\n                if self._paused:\n                    self._paused = False\n                    return  # Will resume via feed_data(b\"\") later\n                self._more_data_available = self.payload.feed_data(b\"\")\n            self.payload.feed_eof()\n            self.done = True\n        elif self._type == ParseState.PARSE_CHUNKED:\n            raise TransferEncodingError(\n                \"Not enough data to satisfy transfer length header.\"\n            )\n\n    def feed_data(\n        self, chunk: bytes, SEP: _SEP = b\"\\r\\n\", CHUNK_EXT: bytes = b\";\"\n    ) -> tuple[PayloadState, bytes]:\n        \"\"\"Receive a chunk of data to process.\n\n        Return:\n            PayloadState - The current state of payload processing.\n                           This function may be called with empty bytes after returning\n                           PAYLOAD_HAS_PENDING_INPUT to continue processing after a pause.\n            bytes - If payload is complete, this is the unconsumed bytes intended for the\n                    next message/payload, b\"\" otherwise.\n        \"\"\"\n        # Read specified amount of bytes\n        if self._type == ParseState.PARSE_LENGTH:\n            if self._chunk_tail:","sourceCodeStart":916,"sourceCodeEnd":952,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/http_parser.py#L916-L952","documentation":"Raised as TransferEncodingError (a BadHttpMessage subclass) when a chunked-encoded body stream reaches EOF before the terminating zero-length chunk (and trailers). HttpPayloadParser.feed_eof, in the PARSE_CHUNKED branch, raises unconditionally: a properly terminated chunked body finishes via the size-0 chunk path, never via EOF. So hitting EOF in this state means the chunked stream was truncated.","triggerScenarios":"A request/response declares 'Transfer-Encoding: chunked' but the connection closes before the final '0\\r\\n\\r\\n' terminator arrives. Fires when feed_eof is called while _type == ParseState.PARSE_CHUNKED.","commonSituations":"The server/client closes the connection mid-chunk without sending the terminating zero-size chunk; a proxy or CDN severing a streaming response; network resets; a misbehaving streaming endpoint that crashes before finishing the chunked frame; clients that give up reading and abort.","solutions":["Ensure the sender of a chunked body always emits the final '0\\r\\n\\r\\n' before closing.","On the receiving side, treat this as a fatal connection error; reconnect and retry idempotent requests.","Inspect intermediaries (proxies, load balancers) that may strip or truncate the terminating chunk.","If streaming cannot be guaranteed to complete, consider a different framing or reconnect logic.","Check the sender's logs for unhandled exceptions during chunk production."],"exampleFix":"# before (server-side handler crashes before write_eof)\r\nresp = web.StreamResponse(headers={'Transfer-Encoding': 'chunked'})\r\nawait resp.prepare(request)\r\nawait resp.write(b'some data')\r\n# ... exception raised here, connection closes without final chunk\r\n\r\n# after (ensure write_eof runs in a finally)\r\nresp = web.StreamResponse()\r\nawait resp.prepare(request)\r\ntry:\r\n    await resp.write(b'some data')\r\nfinally:\r\n    await resp.write_eof()","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from aiohttp.http_exceptions import TransferEncodingError\nimport aiohttp\n\nasync def fetch_chunked(url, *, attempts=3):\n    last = None\n    for i in range(attempts):\n        try:\n            async with aiohttp.ClientSession() as s:\n                async with s.get(url) as r:\n                    return await r.read()\n        except TransferEncodingError as e:\n            last = e\n            await asyncio.sleep(2 ** i)\n    raise last\n","preventionTips":["Ensure chunked senders emit the final '0\\r\\n\\r\\n' terminator.","Retry idempotent requests on truncated chunked streams.","Audit proxies that may strip the terminating chunk.","Always run write_eof() in a finally block when streaming."],"tags":["http-parser","transfer-encoding","chunked","truncated","payload"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}