{"record":{"id":"199e512a479f3673","repo":"aio-libs/aiohttp","slug":"chunked-can-not-be-set-if-content-length-header-is","errorCode":null,"errorMessage":"chunked can not be set if Content-Length header is set","messagePattern":"chunked can not be set if Content-Length header is set","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/client_reqrep.py","lineNumber":1235,"sourceCode":"                )\n            self.compress = compress if isinstance(compress, str) else \"deflate\"\n            self.headers[hdrs.CONTENT_ENCODING] = self.compress\n            self.chunked = True  # enable chunked, no need to deal with length\n\n    def _update_transfer_encoding(self) -> None:\n        \"\"\"Analyze transfer-encoding header.\"\"\"\n        te = self.headers.get(hdrs.TRANSFER_ENCODING, \"\").lower()\n\n        if \"chunked\" in te:\n            if self.chunked:\n                raise ValueError(\n                    \"chunked can not be set \"\n                    'if \"Transfer-Encoding: chunked\" header is set'\n                )\n\n        elif self.chunked:\n            if hdrs.CONTENT_LENGTH in self.headers:\n                raise ValueError(\n                    \"chunked can not be set if Content-Length header is set\"\n                )\n\n            self.headers[hdrs.TRANSFER_ENCODING] = \"chunked\"\n\n    def _update_body_from_data(self, body: Any) -> None:\n        \"\"\"Update request body from data.\"\"\"\n        if body is None:\n            self._body = self._EMPTY_BODY\n            # Set Content-Length to 0 when body is None for methods that expect a body\n            if (\n                self.method not in self.GET_METHODS\n                and not self.chunked\n                and hdrs.CONTENT_LENGTH not in self.headers\n            ):\n                self.headers[hdrs.CONTENT_LENGTH] = \"0\"\n            return\n","sourceCodeStart":1217,"sourceCodeEnd":1253,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/client_reqrep.py#L1217-L1253","documentation":"Raised by ClientRequest._update_transfer_encoding() when chunked transfer encoding is being enabled but a Content-Length header is already present. A message cannot have both a Content-Length (fixed size) and chunked Transfer-Encoding (unknown size); they are mutually exclusive per HTTP semantics, so aiohttp raises ValueError.","triggerScenarios":"Setting headers['Content-Length']='123' AND triggering chunked mode (via a streaming body, compress=True, or chunked=True). _update_transfer_encoding sees self.chunked True and Content-Length in headers, and raises ValueError.","commonSituations":"Pre-setting Content-Length for a body whose actual size is unknown (stream); copy-pasting headers that include Content-Length while passing a generator/async generator body; mixing fixed-length assumptions with chunked producers.","solutions":["For fixed-size bodies, let aiohttp compute Content-Length from the data and don't set it manually.","For streaming/unknown-size bodies, remove any manual Content-Length header.","If you set Content-Length, ensure the body is bytes/str with matching length and not a stream.","Audit header construction to avoid stale Content-Length from a template."],"exampleFix":"# before\nheaders['Content-Length'] = '100'\nawait session.post(url, data=async_gen(), headers=headers)  # ValueError\n\n# after — streaming body, no manual Content-Length\nawait session.post(url, data=async_gen(), headers={k:v for k,v in headers.items() if k.lower()!='content-length'})","handlingStrategy":"validation","validationCode":"def strip_conflicting_length(headers, body):\n    # streaming/unknown-size body cannot have a preset Content-Length\n    if not isinstance(body, (bytes, bytearray, str)):\n        headers.pop('Content-Length', None)\n    return headers","typeGuard":"def body_and_headers_consistent(headers, body) -> bool:\n    streaming = not isinstance(body, (bytes, bytearray, str, type(None)))\n    return not (streaming and any(k.lower() == 'content-length' for k in headers))","tryCatchPattern":"try:\n    await session.post(url, data=stream_gen, headers=headers)\nexcept ValueError as e:\n    if 'Content-Length header is set' in str(e):\n        headers = {k:v for k,v in headers.items() if k.lower() != 'content-length'}\n        await session.post(url, data=stream_gen, headers=headers)\n    else:\n        raise","preventionTips":["Don't set Content-Length when the body is a generator/stream.","Let aiohttp compute Content-Length for bytes/str bodies.","Filter Content-Length out of templated header dicts before streaming requests."],"tags":["client","request","http-headers","transfer-encoding","content-length","chunked"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}