aio-libs/aiohttp · error · ValueError
bad content disposition parameter
Error message
bad content disposition parameter {key!r}={val!r} What it means
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).
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'
Example fix
# before
header = content_disposition_header('attachment', params={'': 'file.txt'})
# ValueError: bad content disposition parameter
# after
header = content_disposition_header('attachment', params={'filename': 'file.txt'}) Defensive patterns
Strategy: validation
Validate before calling
import re
TOKEN_RE = re.compile(r"^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$")
def sanitize_disposition_params(params):
clean = {}
for k, v in params.items():
if k and TOKEN_RE.match(k):
clean[k] = v
else:
logger.warning('Skipping invalid disposition param key: %r', k)
return clean Type guard
import re
def is_valid_param_key(key: str) -> bool:
return bool(key) and bool(re.match(r"^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$", key)) Try / catch
try:
header = content_disposition_header(disptype, params=params)
except ValueError as e:
if 'bad content disposition parameter' in str(e).lower():
params = {k: v for k, v in params.items() if is_valid_param_key(k)}
header = content_disposition_header(disptype, params=params)
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- bad content disposition type
- bad content for quoted-string
- Duplicate ' ' header found.
- Invalid HTTP header
- Transfer-Encoding can't be present with Content-Length
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/aad668458c493afd.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/helpers.py:447
Should be valid extension token (see RFC 2183)
quote_fields performs value quoting to 7-bit MIME headers
according to RFC 7578. Set to quote_fields to False if recipient
can take 8-bit file names and field values.
_charset specifies the charset to use when quote_fields is True.
params is a dict with disposition params.
"""
if not disptype or not (TOKEN > set(disptype)):
raise ValueError(f"bad content disposition type {disptype!r}")
value = disptype
if params:
lparams = []
for key, val in params.items():
if not key or not (TOKEN > set(key)):
raise ValueError(f"bad content disposition parameter {key!r}={val!r}")
if quote_fields:
if key.lower() == "filename":
qval = quote(val, "", encoding=_charset)
lparams.append((key, '"%s"' % qval))
else:
try:
qval = quoted_string(val)
except ValueError:
qval = "".join(
(_charset, "''", quote(val, "", encoding=_charset))
)
lparams.append((key + "*", qval))
else:
lparams.append((key, '"%s"' % qval))
else:
qval = val.replace("\\", "\\\\").replace('"', '\\"')
lparams.append((key, '"%s"' % qval))
sparams = "; ".join("=".join(pair) for pair in lparams)View on GitHub (pinned to d041d4d0fd)