{"id":"74e55085e55a6e54","repo":"aio-libs/aiohttp","slug":"boundary-should-contain-ascii-only-chars","errorCode":null,"errorMessage":"boundary should contain ASCII only chars","messagePattern":"boundary should contain ASCII only chars","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/multipart.py","lineNumber":924,"sourceCode":"\nclass MultipartWriter(Payload):\n    \"\"\"Multipart body writer.\"\"\"\n\n    _value: None\n    # _consumed = False (inherited) - Can be encoded multiple times\n    _autoclose = True  # No file handles, just collects parts in memory\n\n    def __init__(self, subtype: str = \"mixed\", boundary: str | None = None) -> None:\n        boundary = boundary if boundary is not None else uuid.uuid4().hex\n        # The underlying Payload API demands a str (utf-8), not bytes,\n        # so we need to ensure we don't lose anything during conversion.\n        # As a result, require the boundary to be ASCII only.\n        # In both situations.\n\n        try:\n            self._boundary = boundary.encode(\"ascii\")\n        except UnicodeEncodeError:\n            raise ValueError(\"boundary should contain ASCII only chars\") from None\n\n        if len(boundary) > 70:\n            raise ValueError(\"boundary %r is too long (70 chars max)\" % boundary)\n\n        ctype = f\"multipart/{subtype}; boundary={self._boundary_value}\"\n\n        super().__init__(None, content_type=ctype)\n\n        self._parts: list[_Part] = []\n        self._is_form_data = subtype == \"form-data\"\n\n    def __enter__(self) -> \"MultipartWriter\":\n        return self\n\n    def __exit__(\n        self,\n        exc_type: type[BaseException] | None,\n        exc_val: BaseException | None,","sourceCodeStart":906,"sourceCodeEnd":942,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/multipart.py#L906-L942","documentation":"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.","triggerScenarios":"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.","commonSituations":"Copy-pasting a fancy boundary with typographic characters; auto-generating a boundary from user input that contains Unicode; test fixtures using arbitrary strings.","solutions":["Use an ASCII-only boundary: `MultipartWriter(boundary='----WebKitFormBoundary7MA4YWxk')`.","Omit the boundary argument entirely — MultipartWriter generates a random ASCII uuid4 hex by default.","Sanitize user-provided boundary input to ASCII before passing it."],"exampleFix":"// before\nw = MultipartWriter(boundary='——boundary——')  # non-ASCII em-dashes\n// after\nw = MultipartWriter()  # auto-generated ASCII boundary\n","handlingStrategy":"validation","validationCode":"try:\n    boundary.encode('ascii')\nexcept UnicodeEncodeError:\n    raise ValueError('boundary must be ASCII-only')","typeGuard":"def is_ascii_boundary(b: str) -> bool:\n    try:\n        b.encode('ascii')\n        return True\n    except UnicodeEncodeError:\n        return False","tryCatchPattern":"try:\n    writer = MultipartWriter(boundary=boundary)\nexcept ValueError:\n    writer = MultipartWriter()  # fall back to auto-generated ASCII boundary","preventionTips":["Prefer the auto-generated boundary unless you have a specific reason.","Sanitize any dynamic boundary to ASCII before passing it.","Avoid copying boundaries from untrusted sources."],"tags":["multipart","boundary","ascii","writer"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}