{"record":{"id":"aad668458c493afd","repo":"aio-libs/aiohttp","slug":"bad-content-disposition-parameter-key-r-val-r","errorCode":null,"errorMessage":"bad content disposition parameter {key!r}={val!r}","messagePattern":"bad content disposition parameter (.+?)=(.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/helpers.py","lineNumber":447,"sourceCode":"    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                        )\n                        lparams.append((key + \"*\", qval))\n                    else:\n                        lparams.append((key, '\"%s\"' % qval))\n            else:\n                qval = val.replace(\"\\\\\", \"\\\\\\\\\").replace('\"', '\\\\\"')\n                lparams.append((key, '\"%s\"' % qval))\n        sparams = \"; \".join(\"=\".join(pair) for pair in lparams)","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/helpers.py#L429-L465","documentation":"content_disposition_header raises ValueError when a parameter key in the params dict is empty or contains non-token characters. Parameter names in Content-Disposition headers must be valid RFC 2045 tokens (alphanumeric and certain special characters, no spaces or separators).","triggerScenarios":"Calling content_disposition_header with a params dict that has an empty string key, or a key containing invalid characters like spaces, semicolons, or equals signs. Also triggered when set_content_disposition is called with keyword arguments that produce invalid parameter names.","commonSituations":"Building Content-Disposition params from user input or dynamic data without sanitizing keys; using 'filename*' or 'creation-date' which may contain hyphens (hyphens are actually valid tokens); passing a dict with an empty key from a filter that removed all characters.","solutions":["Sanitize parameter keys: remove or replace non-token characters","Ensure keys are non-empty and contain only token characters","Use standard parameter names: 'name', 'filename', 'size'"],"exampleFix":"# before\nheader = content_disposition_header('attachment', params={'': 'file.txt'})\n# ValueError: bad content disposition parameter\n\n# after\nheader = content_disposition_header('attachment', params={'filename': 'file.txt'})","handlingStrategy":"validation","validationCode":"import re\nTOKEN_RE = re.compile(r\"^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$\")\n\ndef sanitize_disposition_params(params):\n    clean = {}\n    for k, v in params.items():\n        if k and TOKEN_RE.match(k):\n            clean[k] = v\n        else:\n            logger.warning('Skipping invalid disposition param key: %r', k)\n    return clean","typeGuard":"import re\ndef is_valid_param_key(key: str) -> bool:\n    return bool(key) and bool(re.match(r\"^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$\", key))","tryCatchPattern":"try:\n    header = content_disposition_header(disptype, params=params)\nexcept ValueError as e:\n    if 'bad content disposition parameter' in str(e).lower():\n        params = {k: v for k, v in params.items() if is_valid_param_key(k)}\n        header = content_disposition_header(disptype, params=params)\n    raise","preventionTips":["Validate parameter keys against RFC token rules before building headers","Never use empty strings as parameter keys","Filter out invalid keys from dynamic/user-provided param dicts"],"tags":["content-disposition","validation","header","rfc-2183"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}