aio-libs/aiohttp · error · RuntimeError

unknown content transfer encoding

Error message

unknown content transfer encoding: {encoding}

What it means

Raised by _decode_content_transfer when the Content-Transfer-Encoding header is not one of base64, quoted-printable, binary, 8bit, or 7bit. Any other token (or a misspelling) yields a RuntimeError.

Solutions

  1. Use one of base64, quoted-printable, binary, 8bit, 7bit for Content-Transfer-Encoding.
  2. If you control the producer, drop CTE and send 8bit/binary with correct Content-Length.
  3. Decode the unsupported transfer encoding externally before/after the reader touches it.
  4. Catch RuntimeError and fall back to raw bytes when CTE is non-standard.

Example fix

// before
Content-Transfer-Encoding: x-uuencode

// after
Content-Transfer-Encoding: base64
Defensive patterns

Strategy: validation

Validate before calling

SUPPORTED_CTE = {'base64', 'quoted-printable', 'binary', '8bit', '7bit'}

def assert_supported_cte(headers):
    cte = headers.get('Content-Transfer-Encoding', '').lower()
    if cte and cte not in SUPPORTED_CTE:
        raise ValueError(f'Unsupported Content-Transfer-Encoding: {cte}')

Type guard

def is_supported_cte(value: object) -> bool:
    return isinstance(value, str) and value.lower() in {'base64', 'quoted-printable', 'binary', '8bit', '7bit'}

Try / catch

try:
    data = part._decode_content_transfer(raw)
except RuntimeError as e:
    if 'transfer encoding' in str(e):
        data = raw  # treat as binary
    else:
        raise

Prevention

When it happens

Trigger: A part carrying Content-Transfer-Encoding such as 'x-uuencode', 'uuencode', 'base-64' (hyphen), or any vendor extension; an empty/odd value that does not match the allowed set.

Common situations: Legacy MIME producers; copy-paste typos; MIME-aware mail clients repurposed for HTTP multipart; custom CTE tokens.

Related errors


AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11). Data as JSON: /api/errors/d3ad72dead8be317. Report an issue: GitHub.

Appendix: source

Thrown at aiohttp/multipart.py:607

                suppress_deflate_header=True,
            )
            yield await d.decompress(data, max_length=self._max_decompress_size)
            while d.data_available:
                yield await d.decompress(b"", max_length=self._max_decompress_size)
        else:
            raise RuntimeError(f"unknown content encoding: {encoding}")

    def _decode_content_transfer(self, data: bytes) -> bytes:
        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING, "").lower()

        if encoding == "base64":
            return base64.b64decode(data)
        elif encoding == "quoted-printable":
            return binascii.a2b_qp(data)
        elif encoding in ("binary", "8bit", "7bit"):
            return data
        else:
            raise RuntimeError(f"unknown content transfer encoding: {encoding}")

    def get_charset(self, default: str) -> str:
        """Returns charset parameter from Content-Type header or default."""
        ctype = self.headers.get(CONTENT_TYPE, "")
        mimetype = parse_mimetype(ctype)
        return mimetype.parameters.get("charset", self._default_charset or default)

    @reify
    def name(self) -> str | None:
        """Returns name specified in Content-Disposition header.

        If the header is missing or malformed, returns None.
        """
        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))
        return content_disposition_filename(params, "name")

    @reify
    def filename(self) -> str | None:

View on GitHub (pinned to d041d4d0fd)