{"record":{"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":928,"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":910,"sourceCodeEnd":946,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/multipart.py#L910-L946","documentation":"MultipartWriter.__init__ requires the boundary string to be ASCII-encodable, because the underlying Payload API serializes the boundary as a str and writes it into the Content-Type header. If boundary.encode('ascii') raises UnicodeEncodeError, ValueError is raised.","triggerScenarios":"Passing a boundary containing non-ASCII characters (e.g. emoji, accented letters, CJK) to MultipartWriter(subtype=..., boundary=...).","commonSituations":"Deriving the boundary from user-supplied data, file names, or locale-specific strings; copy-pasting a boundary from a non-ASCII source.","solutions":["Pass an ASCII-only boundary (RFC 2046 bchars): digits, letters, and '()+,-./_:;=?\\''.","Omit the boundary argument and let MultipartWriter generate one via uuid.uuid4().hex.","Sanitize user input before using it as a boundary: re.sub(r'[^A-Za-z0-9\\'()+,-./_:;=?]', '', value).","Validate with value.isascii() before constructing the writer."],"exampleFix":"// before\nmw = MultipartWriter(boundary='CAFE-菜单')\n\n// after\nmw = MultipartWriter()  # auto-generated ASCII boundary","handlingStrategy":"validation","validationCode":"import re\n_BCHARS = re.compile(r\"[A-Za-z0-9'()+,./_:;=?-]+\\Z\")\n\ndef sanitize_boundary(value: str) -> str:\n    cleaned = re.sub(r\"[^A-Za-z0-9'()+,./_:;=?-]\", '', value)\n    return cleaned or uuid.uuid4().hex","typeGuard":"def is_ascii_boundary(value: object) -> bool:\n    return isinstance(value, str) and value.isascii()","tryCatchPattern":"try:\n    mw = MultipartWriter(boundary=candidate)\nexcept ValueError as e:\n    if 'ASCII' in str(e):\n        mw = MultipartWriter()  # fall back to autogenerated ASCII boundary\n    else:\n        raise","preventionTips":["Omit the boundary argument and let MultipartWriter autogenerate one.","Never derive boundaries from user input or locale-specific strings.","Restrict boundaries to RFC 2046 bchars."],"tags":["multipart","boundary","ascii","validation","writer"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}