{"id":"4ebdcc16d0a59897","repo":"aio-libs/aiohttp","slug":"boundary-value-contains-invalid-characters","errorCode":null,"errorMessage":"boundary value contains invalid characters","messagePattern":"boundary value contains invalid characters","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/multipart.py","lineNumber":983,"sourceCode":"        # Refer to RFCs 7231, 7230, 5234.\n        #\n        # parameter      = token \"=\" ( token / quoted-string )\n        # token          = 1*tchar\n        # quoted-string  = DQUOTE *( qdtext / quoted-pair ) DQUOTE\n        # qdtext         = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text\n        # obs-text       = %x80-FF\n        # quoted-pair    = \"\\\" ( HTAB / SP / VCHAR / obs-text )\n        # tchar          = \"!\" / \"#\" / \"$\" / \"%\" / \"&\" / \"'\" / \"*\"\n        #                  / \"+\" / \"-\" / \".\" / \"^\" / \"_\" / \"`\" / \"|\" / \"~\"\n        #                  / DIGIT / ALPHA\n        #                  ; any VCHAR, except delimiters\n        # VCHAR           = %x21-7E\n        value = self._boundary\n        if re.match(self._valid_tchar_regex, value):\n            return value.decode(\"ascii\")  # cannot fail\n\n        if re.search(self._invalid_qdtext_char_regex, value):\n            raise ValueError(\"boundary value contains invalid characters\")\n\n        # escape %x5C and %x22\n        quoted_value_content = value.replace(b\"\\\\\", b\"\\\\\\\\\")\n        quoted_value_content = quoted_value_content.replace(b'\"', b'\\\\\"')\n\n        return '\"' + quoted_value_content.decode(\"ascii\") + '\"'\n\n    @property\n    def boundary(self) -> str:\n        return self._boundary.decode(\"ascii\")\n\n    def append(self, obj: Any, headers: Mapping[str, str] | None = None) -> Payload:\n        if headers is None:\n            headers = CIMultiDict()\n\n        if isinstance(obj, Payload):\n            obj.headers.update(headers)\n            return self.append_payload(obj)","sourceCodeStart":965,"sourceCodeEnd":1001,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/multipart.py#L965-L1001","documentation":"Raised by MultipartWriter._boundary_value when the boundary, not expressible as a bare HTTP token, must be quoted but contains characters that are invalid even inside a quoted-string (control chars or DEL, per the qdtext grammar). The boundary then cannot be serialized into a valid Content-Type header.","triggerScenarios":"Constructing a MultipartWriter whose boundary contains bytes outside the token charset AND outside the allowed qdtext range (e.g. NUL, CR, LF, other control characters). The token regex fails, so the code attempts to quote it, then the qdtext validity check fails.","commonSituations":"Boundary derived from arbitrary binary/uuid bytes that include control characters; a typo introducing a non-printable character; fuzz-generated boundary values.","solutions":["Restrict the boundary to RFC 2046 token characters: alphanumeric plus `!#$%&'*+-.^_`|~`.","Let MultipartWriter generate its own boundary (uuid4 hex) instead of passing a custom one.","Sanitize any dynamic boundary with a whitelist regex before construction."],"exampleFix":"// before\nw = MultipartWriter(boundary='a\\x00b')\n// after\nimport re\nsafe = re.sub(rb'[^!#$%&\\'*+\\-.^_`|~\\w]', b'', boundary)\nw = MultipartWriter(boundary=safe.decode('ascii'))\n","handlingStrategy":"validation","validationCode":"import re\ntoken_re = re.compile(rb\"\\A[!#$%&'*+\\-.^_`|~\\w]+\\Z\")\nif not token_re.match(boundary.encode('ascii')):\n    raise ValueError('boundary must be token-safe or quotable')","typeGuard":"import re\n_token = re.compile(rb\"\\A[!#$%&'*+\\-.^_`|~\\w]+\\Z\")\n\ndef is_valid_boundary(b: str) -> bool:\n    return bool(_token.match(b.encode('ascii', 'ignore')))","tryCatchPattern":"try:\n    writer = MultipartWriter(boundary=boundary)\nexcept ValueError:\n    writer = MultipartWriter()  # auto-generate a safe boundary","preventionTips":["Restrict boundaries to RFC token characters.","Never derive a boundary from raw binary including control chars.","Validate dynamic boundaries with a whitelist regex."],"tags":["multipart","boundary","validation","writer","http-grammar"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}