python/cpython · error · ValueError
can't have text and binary mode at once
Error message
can't have text and binary mode at once
What it means
Raised by io.open() as a ValueError when the mode string contains both 't' and 'b'. Text mode and binary mode are mutually exclusive: text mode decodes bytes through an encoding with newline translation, binary mode returns raw bytes, so both cannot apply at once.
Source
Thrown at Lib/_pyio.py:217
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")
if binary and errors is not None:
raise ValueError("binary mode doesn't take an errors argument")
if binary and newline is not None:
raise ValueError("binary mode doesn't take a newline argument")
if binary and buffering == 1:
import warnings
warnings.warn("line buffering (buffering=1) isn't supported in binary "
"mode, the default buffer size will be used",
RuntimeWarning, 2)
raw = FileIO(file,
(creating and "x" or "") +
(reading and "r" or "") +View on GitHub (pinned to bc6749cc3b)
Solutions
- Pick one: 'rb'/'wb'/'ab' (+ 'b' variants) for bytes, or 'r'/'w'/'a' with optional 't' for str.
- In mode-building code, derive binary/text from a single variable, not two independent flags that can both be true.
- Validate composed modes against a whitelist before calling open().
Example fix
// before
mode = base_mode + ('t' if text_default else '') # base 'rb' -> 'rbt'
open(path, mode)
// after
if 'b' in base_mode:
mode = base_mode # binary stays binary
else:
mode = base_mode + ('t' if force_t else '')
open(path, mode) Defensive patterns
Strategy: validation
Validate before calling
def build_mode(base: str, binary: bool, update: bool = False) -> str:
assert base in ('r', 'w', 'a', 'x')
return base + ('b' if binary else 't' if False else '') + ('+' if update else '')
# single `binary` boolean makes t/b mutually exclusive by construction Type guard
def mode_consistent(mode: str) -> bool:
s = set(mode)
return not ('t' in s and 'b' in s) Prevention
- Derive 'b'/'t' from one boolean, never two independent flags.
- Prefer omitting 't' — text is the default; only 'b' needs to be explicit.
- Whitelist-validate assembled mode strings before open().
When it happens
Trigger: open('f', 'rtb'), 'wtb', 'r+t+b' — typically a mode assembled programmatically where a default 't' is concatenated onto a user-supplied 'rb'/'wb', or a hand-typed 'rtb'.
Common situations: Mode-building helpers that always append 't' (or default to text) and then receive a base mode that already contains 'b'; merging CLI flags (-t and -b both accepted); documentation examples copied from code that constructed mode strings by concatenation.
Related errors
- can't have read/write/append mode at once
- must have exactly one of read/write/append mode
- binary mode doesn't take an encoding argument
- binary mode doesn't take an errors argument
- binary mode doesn't take a newline argument
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/c12588462776faa5.
Report an issue: GitHub.