python/cpython · error · TypeError

invalid errors: %r

Error message

invalid errors: %r

What it means

Raised by io.open() when the errors argument is supplied and is neither None nor a str. errors names the error handler for text decoding/encoding ('strict', 'replace', 'ignore', 'backslashreplace', ...); the validator rejects any non-string value with this TypeError before the stream is created.

Source

Thrown at Lib/_pyio.py:205

    a BufferedRandom.

    It is also possible to use a string or bytearray as a file for both
    reading and writing. For strings StringIO can be used like a file
    opened in a text mode, and for bytes a BytesIO can be used like a file
    opened in a binary mode.
    """
    if not isinstance(file, int):
        file = os.fspath(file)
    if not isinstance(file, (str, bytes, int)):
        raise TypeError("invalid file: %r" % file)
    if not isinstance(mode, str):
        raise TypeError("invalid mode: %r" % mode)
    if not isinstance(buffering, int):
        raise TypeError("invalid buffering: %r" % buffering)
    if encoding is not None and not isinstance(encoding, str):
        raise TypeError("invalid encoding: %r" % encoding)
    if errors is not None and not isinstance(errors, str):
        raise TypeError("invalid errors: %r" % errors)
    modes = set(mode)
    if modes - set("axrwb+t") or len(mode) > len(modes):
        raise ValueError("invalid mode: %r" % mode)
    creating = "x" in modes
    reading = "r" in modes
    writing = "w" in modes
    appending = "a" in modes
    updating = "+" in modes
    text = "t" in modes
    binary = "b" in modes
    if text and binary:
        raise ValueError("can't have text and binary mode at once")
    if creating + reading + writing + appending > 1:
        raise ValueError("can't have read/write/append mode at once")
    if not (creating or reading or writing or appending):
        raise ValueError("must have exactly one of read/write/append mode")
    if binary and encoding is not None:
        raise ValueError("binary mode doesn't take an encoding argument")

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Pass one of the documented handler names as a str ('strict', 'ignore', 'replace', 'backslashreplace', 'surrogateescape', 'xmlcharrefreplace', 'namereplace') or None.
  2. If the value is an enum/constant object, pass its string value (e.g. member.value).
  3. Fix conditional expressions: errors='strict' if strict_mode else 'replace'.

Example fix

// before
open('f', encoding='utf-8', errors=ErrorHandlers.IGNORE)  # enum object -> TypeError

// after
open('f', encoding='utf-8', errors='ignore')            # str handler name
Defensive patterns

Strategy: type-guard

Validate before calling

HANDLERS = {'strict','ignore','replace','backslashreplace','surrogateescape','xmlcharrefreplace','namereplace'}
if errors is not None:
    assert isinstance(errors, str) and errors in HANDLERS, f'bad errors handler: {errors!r}'
open(path, errors=errors)

Type guard

def valid_errors_handler(e) -> bool:
    return e is None or (isinstance(e, str) and e in {
        'strict','ignore','replace','backslashreplace',
        'surrogateescape','xmlcharrefreplace','namereplace'})

Prevention

When it happens

Trigger: open('f', 'r', errors=None) is fine, but errors=0, errors=['ignore'], or a typo'd constant (e.g. errors=IGNORE vs the string 'ignore') raises it. Also errors=sys.stderr (confusing the stream with its error attribute) or errors='ignore '.strip miswired.

Common situations: Passing module constants instead of their string names; wiring the argument from a settings object whose attribute is an enum or bool instead of str; conditional expressions like errors=strict_mode and 'strict' that evaluate to False.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/fc3411a4014f02e6. Report an issue: GitHub.