python/cpython · error · OSError

"raw" argument must be writable.

Error message

"raw" argument must be writable.

What it means

Raised by the BufferedWriter constructor when raw.writable() is False. BufferedWriter only wraps write-capable raw streams and enforces this at construction, raising OSError with the quoted-argument message. Mirrors the readable check on BufferedReader.

Source

Thrown at Lib/_pyio.py:1256

        with self._read_lock:
            if whence == 1:
                pos -= len(self._read_buf) - self._read_pos
            pos = _BufferedIOMixin.seek(self, pos, whence)
            self._reset_read_buf()
            return pos

class BufferedWriter(_BufferedIOMixin):

    """A buffer for a writeable sequential RawIO object.

    The constructor creates a BufferedWriter for the given writeable raw
    stream. If the buffer_size is not given, it defaults to
    DEFAULT_BUFFER_SIZE.
    """

    def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE):
        if not raw.writable():
            raise OSError('"raw" argument must be writable.')

        _BufferedIOMixin.__init__(self, raw)
        if buffer_size <= 0:
            raise ValueError("invalid buffer size")
        self.buffer_size = buffer_size
        self._write_buf = bytearray()
        self._write_lock = Lock()

    def writable(self):
        return self.raw.writable()

    def write(self, b):
        if isinstance(b, str):
            raise TypeError("can't write str to binary stream")
        with self._write_lock:
            if self.closed:
                raise ValueError("write to closed file")
            # XXX we can implement some more tricks to try and avoid

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Wrap a genuinely writable raw stream: files opened 'wb'/'ab', the pipe write end, or a writable socket.
  2. Implement writable() -> True on custom raw stream classes.
  3. Probe raw.writable() before constructing to produce a domain-specific error.

Example fix

# before
r, w = os.pipe()
writer = io.BufferedWriter(os.fdopen(r, 'rb'))  # read end -> OSError

# after
r, w = os.pipe()
writer = io.BufferedWriter(os.fdopen(w, 'wb'))
Defensive patterns

Strategy: validation

Validate before calling

if not raw.writable():
    raise ValueError("supplied raw stream does not support writing")
writer = io.BufferedWriter(raw)

Type guard

def is_writable_raw(obj) -> bool:
    return hasattr(obj, "writable") and callable(getattr(obj, "write")) and obj.writable()

Try / catch

try:
    writer = io.BufferedWriter(raw)
except OSError as e:
    raise ValueError(f"need the write end, got: {raw!r}") from e

Prevention

When it happens

Trigger: io.BufferedWriter(os.fdopen(rfd, 'rb')) using a pipe read end; wrapping a file opened 'rb'; custom raw stream whose writable() defaults to False (RawIOBase default) because it was not overridden.

Common situations: Swapped pipe ends; passing a socket half that is shut down for writing (shutdown(SHUT_WR) makes writes invalid); custom sink classes forgetting to implement writable().

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/261c7b97011012e2. Report an issue: GitHub.