{"record":{"id":"e625148e4230eed6","repo":"aio-libs/aiohttp","slug":"invalid-content-length-length-r","errorCode":null,"errorMessage":"invalid Content-Length: {length!r}","messagePattern":"invalid Content-Length: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/multipart.py","lineNumber":304,"sourceCode":"        default_charset: str | None = None,\n        max_decompress_size: int = DEFAULT_CHUNK_SIZE,\n        client_max_size: int = sys.maxsize,\n        max_size_error_cls: type[Exception] = ValueError,\n    ) -> None:\n        self.headers = headers\n        self._boundary = boundary\n        self._boundary_len = len(boundary) + 2  # Boundary + \\r\\n\n        self._content = content\n        self._default_charset = default_charset\n        self._at_eof = False\n        self._is_form_data = subtype == \"form-data\"\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None)\n        if length is not None and not (length.isascii() and length.isdigit()):\n            # Reject sign prefixes, underscores, whitespace and non-ASCII\n            # digits that int() would otherwise accept.\n            # https://www.rfc-editor.org/rfc/rfc9110#section-8.6\n            raise ValueError(f\"invalid Content-Length: {length!r}\")\n        self._length = int(length) if length is not None else None\n        self._read_bytes = 0\n        self._unread: deque[bytes] = deque()\n        self._prev_chunk: bytes | None = None\n        self._content_eof = 0\n        self._cache: dict[str, Any] = {}\n        self._max_decompress_size = max_decompress_size\n        self._client_max_size = client_max_size\n        self._max_size_error_cls = max_size_error_cls\n\n    def __aiter__(self) -> Self:\n        return self\n\n    async def __anext__(self) -> bytes:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/multipart.py#L286-L322","documentation":"Raised by BodyPartReader.__init__ when a non-form-data body part carries a Content-Length header whose value is not pure ASCII digits. The library rejects sign prefixes, underscores, whitespace, and non-ASCII digits that Python's int() would otherwise accept, in line with RFC 9110 section 8.6. form-data parts skip this check because per RFC 7578 section 4.8 their Content-Length is ignored.","triggerScenarios":"A multipart body part (subtype != form-data) with a Content-Length header containing a '+'/'-' sign, leading/trailing whitespace, an underscore, or non-ASCII digit characters (e.g. ' 100', '+50', '1_000', fullwidth digits).","commonSituations":"A custom or buggy multipart producer emitting lenient Content-Length values; proxies/gateways that normalize headers in a way int() tolerates but the spec forbids; hand-crafted multipart bodies in tests.","solutions":["Ensure every non-form-data body part's Content-Length header is a bare run of ASCII digits with no sign, whitespace, underscores, or thousands separators.","If you control the producer, omit Content-Length on form-data parts entirely (the reader ignores it for form-data).","If you must parse lenient/malformed input, sanitize the header before constructing the reader, or pre-validate with str.isascii() and str.isdigit()."],"exampleFix":"// before\nContent-Length: +1024\n\n// after\nContent-Length: 1024","handlingStrategy":"validation","validationCode":"def is_valid_content_length(value: str) -> bool:\n    return value is not None and value.isascii() and value.isdigit()\n\n# before constructing the reader, validate each non-form-data part header\ncl = part_headers.get('Content-Length')\nif cl is not None and not is_valid_content_length(cl):\n    raise HTTPBadRequest(text='Malformed Content-Length')","typeGuard":"import re\n_VALID_CONTENT_LENGTH = re.compile(r'\\A[0-9]+\\Z')\ndef is_pure_digit_content_length(v: object) -> bool:\n    return isinstance(v, str) and bool(_VALID_CONTENT_LENGTH.match(v))","tryCatchPattern":"try:\n    part = BodyPartReader(boundary, headers, stream)\nexcept ValueError as e:\n    # invalid Content-Length header on the body part\n    return web.Response(status=400, text=f'Malformed part: {e}')","preventionTips":["Always emit Content-Length as bare ASCII digits with no sign or whitespace.","Omit Content-Length on form-data parts (the reader ignores it there).","Validate incoming part headers at the trust boundary before handing them to MultipartReader."],"tags":["multipart","http-headers","content-length","validation","rfc-9110"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}