RustPython/RustPython · error · ValueError
binary mode doesn't take an encoding argument
Error message
binary mode doesn't take an encoding argument
What it means
ValueError raised when encoding is passed together with a binary mode (a 'b' in the mode string). Binary streams move raw bytes and never decode, so an encoding is meaningless there; encoding, errors, and newline are text-only arguments. The check fires before the file is opened, so nothing is created or truncated as a side effect.
Source
Thrown at Lib/_pyio.py:223
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 "") +
(writing and "w" or "") +
(appending and "a" or "") +
(updating and "+" or ""),
closefd, opener=opener)
result = raw
try:View on GitHub (pinned to aaeab4f754)
Solutions
- Drop encoding (and errors/newline) from binary opens: open(path, 'rb')
- If decoded text is what you want, use text mode: open(path, 'r', encoding='utf-8')
- In wrappers, gate kwargs on the flavor: kwargs = {} if 'b' in mode else {'encoding': enc}
Example fix
# before
with open(path, 'rb', encoding='utf-8') as f:
data = f.read()
# after
with open(path, 'rb') as f:
data = f.read() # bytes
# or, if text was intended:
with open(path, 'r', encoding='utf-8') as f:
text = f.read() Defensive patterns
Strategy: validation
Validate before calling
def open_any(path, mode='r', encoding=None):
kwargs = {} if 'b' in mode else ({'encoding': encoding} if encoding else {})
return open(path, mode, **kwargs) Type guard
def takes_text_kwargs(mode) -> bool:
return 'b' not in mode Prevention
- Keep binary opens bare: open(path, 'rb')
- Decide once whether a code path is text or binary; do not share kwargs
- When migrating text code to binary, grep the call site for encoding/errors/newline
When it happens
Trigger: open(path, 'rb', encoding='utf-8') - usually copy-paste from a text-mode open; a generic wrapper that always forwards **kwargs (including encoding) into open(); one config dict shared by both text and binary opens.
Common situations: Refactoring text I/O to binary formats (e.g. switching to pickle/struct) while leaving encoding in the call; helper functions like read_bytes(path, encoding=...); a global encoding setting from YAML applied to every open() call.
Related errors
- binary mode doesn't take an errors argument
- binary mode doesn't take a newline argument
- can't have text and binary mode at once
- invalid encoding: %r
- invalid errors: %r
AI-assisted analysis of RustPython/RustPython@aaeab4f754 (2026-08-17).
Data as JSON: /api/errors/7efa96d5a2289f1c.
Report an issue: GitHub.