Textualize/rich · error · ValueError
invalid mode {mode!r}
Error message
invalid mode {mode!r} What it means
Progress.open() normalizes the mode string by sorting its characters and only accepts read modes that reduce to 'r', 'rb' (sorted 'br'), or 'rt'. Any other mode — including write/append modes like 'w', 'a', 'wb+', or unusual orderings like 'b+r' — raises ValueError('invalid mode ...') because this API exists solely to track read progress (downloads).
Source
Thrown at rich/progress.py:1346
mode (str): The mode to use to open the file. Only supports "r", "rb" or "rt".
buffering (int): The buffering strategy to use, see :func:`io.open`.
encoding (str, optional): The encoding to use when reading in text mode, see :func:`io.open`.
errors (str, optional): The error handling strategy for decoding errors, see :func:`io.open`.
newline (str, optional): The strategy for handling newlines in text mode, see :func:`io.open`.
total (int, optional): Total number of bytes to read. If none given, os.stat(path).st_size is used.
task_id (TaskID): Task to track. Default is new task.
description (str, optional): Description of task, if new task is created.
Returns:
BinaryIO: A readable file-like object in binary mode.
Raises:
ValueError: When an invalid mode is given.
"""
# normalize the mode (always rb, rt)
_mode = "".join(sorted(mode, reverse=False))
if _mode not in ("br", "rt", "r"):
raise ValueError(f"invalid mode {mode!r}")
# patch buffering to provide the same behaviour as the builtin `open`
line_buffering = buffering == 1
if _mode == "br" and buffering == 1:
warnings.warn(
"line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used",
RuntimeWarning,
)
buffering = -1
elif _mode in ("rt", "r"):
if buffering == 0:
raise ValueError("can't have unbuffered text I/O")
elif buffering == 1:
buffering = -1
# attempt to get the total with `os.stat`
if total is None:
total = stat(file).st_sizeView on GitHub (pinned to 9d8f9a372c)
Solutions
- Use a read mode: progress.open(path, 'rb') for binary or 'r'/'rt' for text.
- For writing, use the builtin open() and update the progress task manually with progress.update(task_id, completed=f.tell()).
- Double-check for typos/extra characters in the mode string (e.g. 'b+r' instead of 'rb').
Example fix
# before
with progress.open('out.bin', 'wb', total=n) as f: # ValueError: invalid mode 'wb'
f.write(data)
# after
with open('out.bin', 'wb') as f:
f.write(data)
progress.update(task_id, completed=f.tell()) Defensive patterns
Strategy: validation
Validate before calling
VALID = ('r', 'rb', 'rt')
mode = ''.join(sorted(mode))
assert mode in VALID, f'Progress.open supports read modes only, got {mode!r}' Try / catch
try:
f = progress.open(path, mode)
except ValueError as e:
if 'invalid mode' in str(e):
f = progress.open(path, 'rb') # normalize to binary read
else:
raise Prevention
- Remember Progress.open is read-only by design — no 'w'/'a' modes.
- Normalize mode strings before passing; only r/rb/rt survive the sorted-character check.
When it happens
Trigger: progress.open('file.bin', 'wb'); progress.open('f.txt', 'w'); any mode containing w/a/x/+ characters, or a mode whose sorted form isn't in ('br','rt','r') such as 'b+r'.
Common situations: Copy-pasting an existing open(path, mode) call into progress.open() while keeping a write mode; assuming Progress.open mirrors the builtin open() semantics; trying to log/capture output into a progress-tracked file.
Related errors
- write
- writelines
- unable to get the total number of bytes, please specify 'tot
- can't have unbuffered text I/O
- invalid value for align, expected "left", "center", or "righ
AI-assisted analysis of Textualize/rich@9d8f9a372c (2026-08-15).
Data as JSON: /api/errors/17a51fe54c037762.
Report an issue: GitHub.