pypa/pip · error · IDNAError

Unsupported error handling "{errors}"

Error message

Unsupported error handling "{errors}"

What it means

Raised by idna's Codec.encode (the stateless codec used by str.encode('idna2008')) when the errors parameter is anything other than 'strict'. The IDNA 2008 codec intentionally supports only strict error handling — all encoding failures must surface as IDNAError — so passing 'ignore', 'replace', 'backslashreplace', etc. is rejected immediately.

Source

Thrown at src/pip/_vendor/idna/codec.py:20

from typing import Any, Optional

from .core import IDNAError, _unicode_dots_re, alabel, decode, encode, ulabel


class Codec(codecs.Codec):
    """Stateless IDNA 2008 codec.

    Implements the :class:`codecs.Codec` protocol so that the whole-domain
    encoder (:func:`idna.encode`) and decoder (:func:`idna.decode`) are
    accessible through the standard codec machinery as ``"idna2008"``.

    Only the ``"strict"`` error handler is supported; any other handler
    raises :exc:`~idna.IDNAError`.
    """

    def encode(self, data: str, errors: str = "strict") -> tuple[bytes, int]:  # ty: ignore[invalid-method-override]
        if errors != "strict":
            raise IDNAError(f'Unsupported error handling "{errors}"')

        if not data:
            return b"", 0

        return encode(data), len(data)

    def decode(self, data: bytes, errors: str = "strict") -> tuple[str, int]:  # ty: ignore[invalid-method-override]
        if errors != "strict":
            raise IDNAError(f'Unsupported error handling "{errors}"')

        if not data:
            return "", 0

        return decode(data), len(data)


class IncrementalEncoder(codecs.BufferedIncrementalEncoder):
    """Incremental IDNA 2008 encoder.

View on GitHub (pinned to f399c37189)

Solutions

  1. Omit the errors argument (it defaults to 'strict') or explicitly pass errors='strict'.
  2. If you need lenient handling, validate/normalize the domain before encoding and handle IDNAError yourself.
  3. Use idna.encode(domain) directly instead of the codec machinery if you need the full API.

Example fix

# before
encoded = 'café.com'.encode('idna2008', errors='ignore')  # raises

# after
encoded = 'café.com'.encode('idna2008')  # strict by default
Defensive patterns

Strategy: validation

Validate before calling

def safe_idna_encode(domain):
    return domain.encode('idna2008')  # errors defaults to 'strict'

Type guard

def is_valid_errors_value(errors: str) -> bool:
    return errors == 'strict'

Try / catch

from idna.core import IDNAError
try:
    encoded = domain.encode('idna2008')
except IDNAError:
    encoded = domain.encode('ascii', 'ignore')  # fallback for display

Prevention

When it happens

Trigger: Calling 'some-string'.encode('idna2008', errors='ignore') or invoking the codec's encode method with a non-strict errors argument. Also triggered indirectly by libraries that pass a default errors handler to all codecs.

Common situations: A URL-processing library generically passes errors='replace' to all registered codecs; developer assumes idna works like utf-8 with lenient error modes; code copied from a utf-8 example.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/1398d4068b9ca5f3. Report an issue: GitHub.