python/cpython · error · ValueError
binary mode doesn't take an errors argument
Error message
binary mode doesn't take an errors argument
What it means
Raised by io.open() as a ValueError when binary mode ('b') is combined with a non-None errors argument. The errors handler governs text encode/decode failures; a binary stream performs no codec work, so the argument is rejected.
Source
Thrown at Lib/_pyio.py:225
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 "") +
(writing and "w" or "") +
(appending and "a" or "") +
(updating and "+" or ""),
closefd, opener=opener)
result = raw
try:
line_buffering = False
if buffering == 1 or buffering < 0 and raw._isatty_open_only():View on GitHub (pinned to bc6749cc3b)
Solutions
- Remove the errors argument for binary opens.
- Conditionally build kwargs: include errors (and encoding) only when 'b' not in mode.
- If you wanted lenient decoding, you are handling text — use text mode with errors='replace'.
Example fix
// before
with open(path, 'rb', errors='ignore') as f: # ValueError
data = f.read()
// after
with open(path, 'rb') as f:
data = f.read()
# or, if text was intended:
with open(path, 'r', encoding='utf-8', errors='ignore') as f:
text = f.read() Defensive patterns
Strategy: validation
Validate before calling
def open_any(path, mode='r', encoding=None, errors=None, newline=None):
if 'b' in mode:
return open(path, mode) # binary: no text kwargs at all
return open(path, mode, encoding=encoding, errors=errors, newline=newline) Type guard
def text_kwargs_allowed(mode: str) -> bool:
return 'b' not in mode Prevention
- Route errors= (and encoding=) through the same text-only gate in shared helpers.
- When converting 'r' to 'rb' for speed, strip the text kwargs in the same edit.
- Encode a project-level open() wrapper so this rule is applied in exactly one place.
When it happens
Trigger: open('f.bin', 'wb', errors='replace'), or wrappers that unconditionally forward errors=... while the mode is binary. Often appears together with error 170 when both encoding and errors are threaded through every call.
Common situations: Shared open helpers with errors='replace' defaults; migrating a text-mode call to binary for speed while keeping the error-handler kwarg; copy-pasted open() lines edited from 'r' to 'rb' but leaving the kwargs.
Related errors
- can't have text and binary mode at once
- binary mode doesn't take an encoding argument
- binary mode doesn't take a newline argument
- invalid errors: %r
- can't have read/write/append mode at once
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/2bd9f3b56456f6fe.
Report an issue: GitHub.