aio-libs/aiohttp · error · ValueError

boundary should contain ASCII only chars

Error message

boundary should contain ASCII only chars

What it means

Raised by MultipartWriter.__init__ when the user-supplied boundary string cannot be encoded as ASCII. The Payload API requires the boundary to be a str convertible losslessly to bytes, so non-ASCII characters are rejected up front.

Source

Thrown at aiohttp/multipart.py:924

class MultipartWriter(Payload):
    """Multipart body writer."""

    _value: None
    # _consumed = False (inherited) - Can be encoded multiple times
    _autoclose = True  # No file handles, just collects parts in memory

    def __init__(self, subtype: str = "mixed", boundary: str | None = None) -> None:
        boundary = boundary if boundary is not None else uuid.uuid4().hex
        # The underlying Payload API demands a str (utf-8), not bytes,
        # so we need to ensure we don't lose anything during conversion.
        # As a result, require the boundary to be ASCII only.
        # In both situations.

        try:
            self._boundary = boundary.encode("ascii")
        except UnicodeEncodeError:
            raise ValueError("boundary should contain ASCII only chars") from None

        if len(boundary) > 70:
            raise ValueError("boundary %r is too long (70 chars max)" % boundary)

        ctype = f"multipart/{subtype}; boundary={self._boundary_value}"

        super().__init__(None, content_type=ctype)

        self._parts: list[_Part] = []
        self._is_form_data = subtype == "form-data"

    def __enter__(self) -> "MultipartWriter":
        return self

    def __exit__(
        self,
        exc_type: type[BaseException] | None,
        exc_val: BaseException | None,

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Use an ASCII-only boundary: `MultipartWriter(boundary='----WebKitFormBoundary7MA4YWxk')`.
  2. Omit the boundary argument entirely — MultipartWriter generates a random ASCII uuid4 hex by default.
  3. Sanitize user-provided boundary input to ASCII before passing it.

Example fix

// before
w = MultipartWriter(boundary='——boundary——')  # non-ASCII em-dashes
// after
w = MultipartWriter()  # auto-generated ASCII boundary
Defensive patterns

Strategy: validation

Validate before calling

try:
    boundary.encode('ascii')
except UnicodeEncodeError:
    raise ValueError('boundary must be ASCII-only')

Type guard

def is_ascii_boundary(b: str) -> bool:
    try:
        b.encode('ascii')
        return True
    except UnicodeEncodeError:
        return False

Try / catch

try:
    writer = MultipartWriter(boundary=boundary)
except ValueError:
    writer = MultipartWriter()  # fall back to auto-generated ASCII boundary

Prevention

When it happens

Trigger: Constructing `MultipartWriter(boundary='…')` with a boundary containing non-ASCII characters (e.g. Unicode dashes, emoji, accented letters). The encode('ascii') call fails and the UnicodeEncodeError is converted to a ValueError.

Common situations: Copy-pasting a fancy boundary with typographic characters; auto-generating a boundary from user input that contains Unicode; test fixtures using arbitrary strings.

Related errors


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