aio-libs/aiohttp · error · ValueError

bad content disposition type {disptype!r}

Error message

bad content disposition type {disptype!r}

What it means

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.

Source

Thrown at aiohttp/helpers.py:440

    """Sets ``Content-Disposition`` header for MIME.

    This is the MIME payload Content-Disposition header from RFC 2183
    and RFC 7579 section 4.2, not the HTTP Content-Disposition from
    RFC 6266.

    disptype is a disposition type: inline, attachment, form-data.
    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))
                        )

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Pass a bare token like 'attachment', 'inline', or 'form-data'.
  2. Validate disptype against TOKEN before calling.
  3. Put parameters in the params dict, not appended to disptype.

Example fix

// before
content_disposition_header('attachment; name="x"')
// after
content_disposition_header('attachment', params={'name': 'x'})
Defensive patterns

Strategy: validation

Validate before calling

import re
TOKEN = re.compile(r"^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$")
def safe_disptype(t):
    if not TOKEN.fullmatch(t):
        raise ValueError(f'bad disptype {t!r}')
    return t

Type guard

def is_valid_disptype(t) -> bool:
    import re
    TOKEN = set("!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
    return bool(t) and TOKEN > set(t)

Prevention

When it happens

Trigger: content_disposition_header('') or content_disposition_header('attach ment') (space), content_disposition_header('attach"ment') (quote), or a disposition type with '/' .

Common situations: Building Content-Disposition from unvalidated user input; templating disptype with whitespace; passing a MIME-style 'attachment; x' blob as the disptype.

Related errors


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/e03301d022a79229.json. Report an issue: GitHub.