{"id":"1880818c3e2a2de5","repo":"aio-libs/aiohttp","slug":"boundary-r-is-too-long-70-chars-max","errorCode":null,"errorMessage":"boundary %r is too long (70 chars max)","messagePattern":"boundary %r is too long \\(70 chars max\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/multipart.py","lineNumber":837,"sourceCode":"                max_field_size=self._max_field_size,\n                max_headers=self._max_headers,\n                max_size_error_cls=self._max_size_error_cls,\n            )\n        else:\n            return self.part_reader_cls(\n                self._boundary,\n                headers,\n                self._content,\n                subtype=self._mimetype.subtype,\n                default_charset=self._default_charset,\n                client_max_size=self._client_max_size,\n                max_size_error_cls=self._max_size_error_cls,\n            )\n\n    def _get_boundary(self) -> str:\n        boundary = self._mimetype.parameters[\"boundary\"]\n        if len(boundary) > 70:\n            raise ValueError(\"boundary %r is too long (70 chars max)\" % boundary)\n\n        return boundary\n\n    async def _readline(self) -> bytes:\n        if self._unread:\n            return self._unread.pop()\n        return await self._content.readline()\n\n    async def _read_until_first_boundary(self) -> None:\n        while True:\n            chunk = await self._readline()\n            if chunk == b\"\":\n                raise ValueError(f\"Could not find starting boundary {self._boundary!r}\")\n            chunk = chunk.rstrip()\n            if chunk == self._boundary:\n                return\n            elif chunk == self._boundary + b\"--\":\n                self._at_eof = True","sourceCodeStart":819,"sourceCodeEnd":855,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/multipart.py#L819-L855","documentation":"Raised by MultipartReader._get_boundary() when the boundary parameter extracted from the Content-Type header exceeds 70 characters. RFC 2046 §5.1.1 caps boundary length at 70 characters, so aiohttp enforces this on the reader side to reject malformed/abusive bodies before processing.","triggerScenarios":"Receiving a multipart response/request whose Content-Type boundary parameter is longer than 70 chars. Constructed during MultipartReader.__init__ via _get_boundary().","commonSituations":"A buggy sender generating overlong boundaries; an attacker crafting a header-bomb style boundary; a misconfigured framework concatenating data into the boundary.","solutions":["Fix the sender to emit a boundary ≤ 70 characters (RFC 2046 limit).","If you cannot change the sender, reject the message before parsing based on Content-Type inspection.","Treat the ValueError as a 400 Bad Request in handlers."],"exampleFix":"// before\nreader = await response.multipart()  # boundary 80 chars -> ValueError\n// after\n# fix the writer side:\nwriter = MultipartWriter(boundary='short-boundary')  # <= 70 chars\n","handlingStrategy":"validation","validationCode":"import re\nm = re.search(r'boundary=([^;]+)', response.headers.get('Content-Type', ''))\nif m and len(m.group(1).strip('\"')) > 70:\n    raise ValueError('boundary exceeds RFC 2046 limit')","typeGuard":"def boundary_within_limit(content_type: str) -> bool:\n    import re\n    m = re.search(r'boundary=([^;]+)', content_type)\n    return bool(m) and len(m.group(1).strip('\"')) <= 70","tryCatchPattern":"try:\n    reader = await response.multipart()\nexcept ValueError as e:\n    if 'too long' in str(e):\n        return web.Response(status=400, text='boundary too long')\n    raise","preventionTips":["Inspect boundary length before constructing the reader.","Reject overlong boundaries as protocol violations.","Educate upstream on the 70-char RFC limit."],"tags":["multipart","boundary","protocol","validation"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}