python/cpython · error · ValueError
unknown mode: %r
Error message
unknown mode: %r
What it means
Raised by io.open() as a ValueError ('unknown mode') when, after building the buffered layer, none of updating/creating/writing/appending/reading matched a buffer class. Earlier validation already requires exactly one of r/w/a/x, so through the public open() this branch is dead code — a defensive assertion against internal inconsistency or patched behavior.
Source
Thrown at Lib/_pyio.py:261
if buffering == 1 or buffering < 0 and raw._isatty_open_only():
buffering = -1
line_buffering = True
if buffering < 0:
buffering = max(min(raw._blksize, 8192 * 1024), DEFAULT_BUFFER_SIZE)
if buffering < 0:
raise ValueError("invalid buffering size")
if buffering == 0:
if binary:
return result
raise ValueError("can't have unbuffered text I/O")
if updating:
buffer = BufferedRandom(raw, buffering)
elif creating or writing or appending:
buffer = BufferedWriter(raw, buffering)
elif reading:
buffer = BufferedReader(raw, buffering)
else:
raise ValueError("unknown mode: %r" % mode)
result = buffer
if binary:
return result
encoding = text_encoding(encoding)
text = TextIOWrapper(buffer, encoding, errors, newline, line_buffering)
result = text
text.mode = mode
return result
except:
result.close()
raise
# Define a default pure-Python implementation for open_code()
# that does not allow hooks. Warn on first use. Defined for tests.
def _open_code_with_warning(path):
"""Opens the provided file with mode ``'rb'``. This function
should be used when the intent is to treat the contents as
executable code.View on GitHub (pinned to bc6749cc3b)
Solutions
- Use a standard mode string ('r', 'w', 'a', 'x' plus 'b'/'+'/'t'); the normal validators will then guide you.
- If you monkeypatched open/_pyio internals, undo the patch or fix the patched flag computation.
- In forks of this logic, ensure the buffer-class selection covers the same cases your validation admits.
Defensive patterns
Strategy: validation
Validate before calling
assert mode in {'r','w','a','x'} | {m+'+' for m in 'rwax'} | {m+c for m in 'rwax' for c in ('b','t','+b','+t')}, mode
open(path, mode) Prevention
- Whitelist mode strings at the config/CLI boundary; never free-form-build them.
- If this appears at runtime, suspect monkeypatched open/_pyio internals, not the mode string.
When it happens
Trigger: Not reachable via normal open() calls: mode has passed 'must have exactly one of read/write/append mode' by this point. Could only fire with monkeypatched mode flags, a fork of _pyio with modified validation, or direct misuse of the internal code path.
Common situations: Users encounter this string only when grepping the stdlib source or running heavily patched IO stacks (test mocks that stub the mode-flag computation, vendored variants of open()).
Related errors
- can't have text and binary mode at once
- can't have read/write/append mode at once
- must have exactly one of read/write/append mode
- invalid buffering size
- invalid mode: %r
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/61d69415e507f75d.
Report an issue: GitHub.