{"id":"e03301d022a79229","repo":"aio-libs/aiohttp","slug":"bad-content-disposition-type-disptype-r","errorCode":null,"errorMessage":"bad content disposition type {disptype!r}","messagePattern":"bad content disposition type (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/helpers.py","lineNumber":440,"sourceCode":"    \"\"\"Sets ``Content-Disposition`` header for MIME.\n\n    This is the MIME payload Content-Disposition header from RFC 2183\n    and RFC 7579 section 4.2, not the HTTP Content-Disposition from\n    RFC 6266.\n\n    disptype is a disposition type: inline, attachment, form-data.\n    Should be valid extension token (see RFC 2183)\n\n    quote_fields performs value quoting to 7-bit MIME headers\n    according to RFC 7578. Set to quote_fields to False if recipient\n    can take 8-bit file names and field values.\n\n    _charset specifies the charset to use when quote_fields is True.\n\n    params is a dict with disposition params.\n    \"\"\"\n    if not disptype or not (TOKEN > set(disptype)):\n        raise ValueError(f\"bad content disposition type {disptype!r}\")\n\n    value = disptype\n    if params:\n        lparams = []\n        for key, val in params.items():\n            if not key or not (TOKEN > set(key)):\n                raise ValueError(f\"bad content disposition parameter {key!r}={val!r}\")\n            if quote_fields:\n                if key.lower() == \"filename\":\n                    qval = quote(val, \"\", encoding=_charset)\n                    lparams.append((key, '\"%s\"' % qval))\n                else:\n                    try:\n                        qval = quoted_string(val)\n                    except ValueError:\n                        qval = \"\".join(\n                            (_charset, \"''\", quote(val, \"\", encoding=_charset))\n                        )","sourceCodeStart":422,"sourceCodeEnd":458,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/helpers.py#L422-L458","documentation":"Raised by content_disposition_header when disptype is empty or contains characters outside the HTTP TOKEN set (must be a subset of TOKEN: printable ASCII minus separators/controls). The disposition type (inline/attachment/form-data) must be a valid RFC 9110 token.","triggerScenarios":"content_disposition_header('') or content_disposition_header('attach ment') (space), content_disposition_header('attach\"ment') (quote), or a disposition type with '/' .","commonSituations":"Building Content-Disposition from unvalidated user input; templating disptype with whitespace; passing a MIME-style 'attachment; x' blob as the disptype.","solutions":["Pass a bare token like 'attachment', 'inline', or 'form-data'.","Validate disptype against TOKEN before calling.","Put parameters in the params dict, not appended to disptype."],"exampleFix":"// before\ncontent_disposition_header('attachment; name=\"x\"')\n// after\ncontent_disposition_header('attachment', params={'name': 'x'})","handlingStrategy":"validation","validationCode":"import re\nTOKEN = re.compile(r\"^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$\")\ndef safe_disptype(t):\n    if not TOKEN.fullmatch(t):\n        raise ValueError(f'bad disptype {t!r}')\n    return t","typeGuard":"def is_valid_disptype(t) -> bool:\n    import re\n    TOKEN = set(\"!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\")\n    return bool(t) and TOKEN > set(t)","tryCatchPattern":null,"preventionTips":["Use canonical tokens: inline, attachment, form-data.","Keep parameters in the params dict, not in disptype.","Validate disptype against TOKEN before constructing the header."],"tags":["content-disposition","validation","mime","headers"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}