{"id":"cf11ef0a13815650","repo":"aio-libs/aiohttp","slug":"boundary-missed-for-content-type-s","errorCode":null,"errorMessage":"boundary missed for Content-Type: %s","messagePattern":"boundary missed for Content-Type: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/multipart.py","lineNumber":695,"sourceCode":"    #: None points to type(self)\n    multipart_reader_cls: type[\"MultipartReader\"] | None = None\n    #: Body part reader class for non multipart/* content types.\n    part_reader_cls = BodyPartReader\n\n    def __init__(\n        self,\n        headers: Mapping[str, str],\n        content: StreamReader,\n        *,\n        client_max_size: int = sys.maxsize,\n        max_field_size: int = 8190,\n        max_headers: int = 128,\n        max_size_error_cls: type[Exception] = ValueError,\n    ) -> None:\n        self._mimetype = parse_mimetype(headers[CONTENT_TYPE])\n        assert self._mimetype.type == \"multipart\", \"multipart/* content type expected\"\n        if \"boundary\" not in self._mimetype.parameters:\n            raise ValueError(\n                \"boundary missed for Content-Type: %s\" % headers[CONTENT_TYPE]\n            )\n\n        self.headers = headers\n        self._boundary = (\"--\" + self._get_boundary()).encode()\n        self._client_max_size = client_max_size\n        self._content = content\n        self._default_charset: str | None = None\n        self._last_part: MultipartReader | BodyPartReader | None = None\n        self._max_field_size = max_field_size\n        self._max_headers = max_headers\n        self._max_size_error_cls = max_size_error_cls\n        self._at_eof = False\n        self._at_bof = True\n        self._unread: list[bytes] = []\n\n    def __aiter__(self) -> Self:\n        return self","sourceCodeStart":677,"sourceCodeEnd":713,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/multipart.py#L677-L713","documentation":"Raised by MultipartReader.__init__ when the Content-Type header indicates a multipart/* type but lacks the required 'boundary' parameter. Per RFC 2046 §5.1.1 the boundary delimiter is mandatory for multipart bodies, so the reader cannot segment the stream without it.","triggerScenarios":"Constructing a MultipartReader (directly or via `response.multipart()` / `request.multipart()`) where the Content-Type is e.g. 'multipart/form-data' with no `; boundary=...`. The assert for multipart type passes but the boundary check fails.","commonSituations":"Upstream sends `Content-Type: multipart/form-data` and forgets the boundary (bug); a proxy strips the boundary parameter; manually crafted responses/requests; Content-Type header truncated by a size limit.","solutions":["Ensure the sender includes a valid boundary in the Content-Type header.","If you control the response, use MultipartWriter which generates the boundary automatically.","Validate the Content-Type header before calling multipart() and reject with a clear error."],"exampleFix":"// before\nreader = await response.multipart()  # no boundary -> ValueError\n// after\nif 'boundary=' not in response.headers.get('Content-Type', ''):\n    raise ValueError('upstream omitted multipart boundary')\nreader = await response.multipart()\n","handlingStrategy":"validation","validationCode":"ctype = response.headers.get('Content-Type', '')\nif 'multipart/' in ctype and 'boundary=' not in ctype:\n    raise ValueError('Content-Type missing boundary parameter')","typeGuard":"import re\n\ndef has_boundary(content_type: str) -> bool:\n    return bool(re.search(r'boundary=', content_type, re.I))","tryCatchPattern":"try:\n    reader = await response.multipart()\nexcept ValueError as e:\n    # missing boundary — reject upstream\n    raise BadUpstream(str(e))","preventionTips":["Validate Content-Type contains a boundary before calling multipart().","Use MultipartWriter on the producer side so the boundary is always set.","Reject multipart responses lacking a boundary at the client boundary."],"tags":["multipart","content-type","boundary","protocol"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}