python/cpython · error · TypeError
invalid buffering: %r
Error message
invalid buffering: %r
What it means
Raised by io.open() when the buffering argument is not an int. buffering selects the buffer strategy (-1 default, 0 unbuffered, 1 line-buffered, >1 buffer size), and the validator only accepts ints — bool passes (it is an int subclass), but None, floats, and strings do not.
Source
Thrown at Lib/_pyio.py:201
'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open
a file in a binary mode, the returned class varies: in read binary
mode, it returns a BufferedReader; in write binary and append binary
modes, it returns a BufferedWriter, and in read/write mode, it returns
a BufferedRandom.
It is also possible to use a string or bytearray as a file for both
reading and writing. For strings StringIO can be used like a file
opened in a text mode, and for bytes a BytesIO can be used like a file
opened in a binary mode.
"""
if not isinstance(file, int):
file = os.fspath(file)
if not isinstance(file, (str, bytes, int)):
raise TypeError("invalid file: %r" % file)
if not isinstance(mode, str):
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")View on GitHub (pinned to bc6749cc3b)
Solutions
- Omit the buffering argument entirely when you want the default (-1).
- Coerce explicit sizes to int: buffering=int(size).
- Validate config-supplied values: accept only ints before calling open().
Example fix
// before
buf = config['buffer_size'] # e.g. "8192" from JSON
open('f.bin', 'rb', buffering=buf) # TypeError: invalid buffering: '8192'
// after
buf = int(config['buffer_size'])
open('f.bin', 'rb', buffering=buf) Defensive patterns
Strategy: validation
Validate before calling
if buffering is not None:
if not isinstance(buffering, int) or isinstance(buffering, bool) and buffering is False:
pass
buffering = int(buffering) if not isinstance(buffering, int) else buffering
assert buffering >= 0, 'buffering must be >= 0'
open(path, buffering=buffering if buffering is not None else -1) Type guard
def valid_buffering(b) -> bool:
return b is None or (isinstance(b, int) and not isinstance(b, bool) and b >= -1) Prevention
- Omit buffering to get the default instead of passing None.
- Coerce config/JSON-sourced sizes with int() at load time.
- Keep sizes as ints in arithmetic (avoid float multiplies like 1024 * 0.5).
When it happens
Trigger: open('f', 'rb', buffering=None), buffering=8192.0 (float), buffering='8192', or buffering read from JSON/config as a string or float. Note open() defaults buffering=-1, so this only fires when the argument is passed explicitly.
Common situations: Config files or JSON supplying buffering as a string number; a size computed with float arithmetic (e.g. 1024*0.5); passing None intending 'default' — the caller should simply omit the argument for the default.
Related errors
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/04d8eb8118159311.
Report an issue: GitHub.