aio-libs/aiohttp · error · ValueError

boundary %r is too long (70 chars max)

Error message

boundary %r is too long (70 chars max)

What it means

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.

Source

Thrown at aiohttp/multipart.py:837

                max_field_size=self._max_field_size,
                max_headers=self._max_headers,
                max_size_error_cls=self._max_size_error_cls,
            )
        else:
            return self.part_reader_cls(
                self._boundary,
                headers,
                self._content,
                subtype=self._mimetype.subtype,
                default_charset=self._default_charset,
                client_max_size=self._client_max_size,
                max_size_error_cls=self._max_size_error_cls,
            )

    def _get_boundary(self) -> str:
        boundary = self._mimetype.parameters["boundary"]
        if len(boundary) > 70:
            raise ValueError("boundary %r is too long (70 chars max)" % boundary)

        return boundary

    async def _readline(self) -> bytes:
        if self._unread:
            return self._unread.pop()
        return await self._content.readline()

    async def _read_until_first_boundary(self) -> None:
        while True:
            chunk = await self._readline()
            if chunk == b"":
                raise ValueError(f"Could not find starting boundary {self._boundary!r}")
            chunk = chunk.rstrip()
            if chunk == self._boundary:
                return
            elif chunk == self._boundary + b"--":
                self._at_eof = True

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Fix the sender to emit a boundary ≤ 70 characters (RFC 2046 limit).
  2. If you cannot change the sender, reject the message before parsing based on Content-Type inspection.
  3. Treat the ValueError as a 400 Bad Request in handlers.

Example fix

// before
reader = await response.multipart()  # boundary 80 chars -> ValueError
// after
# fix the writer side:
writer = MultipartWriter(boundary='short-boundary')  # <= 70 chars
Defensive patterns

Strategy: validation

Validate before calling

import re
m = re.search(r'boundary=([^;]+)', response.headers.get('Content-Type', ''))
if m and len(m.group(1).strip('"')) > 70:
    raise ValueError('boundary exceeds RFC 2046 limit')

Type guard

def boundary_within_limit(content_type: str) -> bool:
    import re
    m = re.search(r'boundary=([^;]+)', content_type)
    return bool(m) and len(m.group(1).strip('"')) <= 70

Try / catch

try:
    reader = await response.multipart()
except ValueError as e:
    if 'too long' in str(e):
        return web.Response(status=400, text='boundary too long')
    raise

Prevention

When it happens

Trigger: Receiving a multipart response/request whose Content-Type boundary parameter is longer than 70 chars. Constructed during MultipartReader.__init__ via _get_boundary().

Common situations: A buggy sender generating overlong boundaries; an attacker crafting a header-bomb style boundary; a misconfigured framework concatenating data into the boundary.

Related errors


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/1880818c3e2a2de5.json. Report an issue: GitHub.