netdata/netdata · error · ValueError

unbuffered streams must be binary

Error message

unbuffered streams must be binary

What it means

Same makefile backport, buffering branch: when buffering == 0 (unbuffered) the function can only return the raw SocketIO object, which is inherently binary. Requesting an unbuffered text stream (mode without 'b' together with buffering=0) is impossible to satisfy, so ValueError is raised before a broken stream object escapes.

Source

Thrown at src/collectors/python.d.plugin/python_modules/urllib3/packages/backports/makefile.py:41

        )
    writing = "w" in mode
    reading = "r" in mode or not writing
    assert reading or writing
    binary = "b" in mode
    rawmode = ""
    if reading:
        rawmode += "r"
    if writing:
        rawmode += "w"
    raw = SocketIO(self, rawmode)
    self._makefile_refs += 1
    if buffering is None:
        buffering = -1
    if buffering < 0:
        buffering = io.DEFAULT_BUFFER_SIZE
    if buffering == 0:
        if not binary:
            raise ValueError("unbuffered streams must be binary")
        return raw
    if reading and writing:
        buffer = io.BufferedRWPair(raw, raw, buffering)
    elif reading:
        buffer = io.BufferedReader(raw, buffering)
    else:
        assert writing
        buffer = io.BufferedWriter(raw, buffering)
    if binary:
        return buffer
    text = io.TextIOWrapper(buffer, encoding, errors, newline)
    text.mode = mode
    return text

View on GitHub (pinned to 4864de85e2)

Solutions

  1. Add 'b' to the mode when you need buffering=0, and decode/encode bytes explicitly at the call site
  2. Or keep text mode and accept default buffering (omit buffering or pass buffering=-1 / a positive int) — TextIOWrapper requires a buffer by design
  3. Wrap the raw binary stream manually: raw = sock.makefile('rb', buffering=0) then wrap with io.TextIOWrapper(io.BufferedReader(raw)) if you need both

Example fix

# before
f = wrapped_sock.makefile('r', buffering=0)
# ValueError: unbuffered streams must be binary

# after
f = wrapped_sock.makefile('rb', buffering=0)
data = f.read().decode('utf-8')  # explicit decode
Defensive patterns

Strategy: validation

Validate before calling

def open_sock_stream(sock, mode='r', buffering=-1, **kw):
    if buffering == 0:
        assert 'b' in mode, 'buffering=0 requires binary mode'
        return sock.makefile(mode + ('b' if 'b' not in mode else ''), buffering=0)
    return sock.makefile(mode, buffering=buffering, **kw)

Type guard

def unbuffered_ok(mode, buffering):
    return buffering != 0 or 'b' in mode

Try / catch

try:
    f = sock.makefile('r', buffering=0)
except ValueError as e:
    if 'unbuffered streams must be binary' in str(e):
        f = sock.makefile('rb', buffering=0)
    else:
        raise

Prevention

When it happens

Trigger: Calling makefile('r', buffering=0) or makefile('w', buffering=0) — text mode with zero buffering — on a SecureTransport-wrapped socket (Python 3 path via urllib3's backport).

Common situations: Performance-tuning copy-paste that sets buffering=0 without realizing it forces binary; protocol code that handles the returned object as str and crashes later if the guard were absent; porting C-style unbuffered IO expectations to Python sockets.

Related errors


AI-assisted analysis of netdata/netdata@4864de85e2 (2026-08-15). Data as JSON: /api/errors/37d9bfc0b5a583e0. Report an issue: GitHub.