python/cpython · error · OSError
"writer" argument must be writable.
Error message
"writer" argument must be writable.
What it means
Raised by io.BufferedRWPair.__init__ when the object passed as writer does not report itself as writable via its writable() method. It is the second of two constructor sanity checks (after the reader.readable() check) that the supplied raw IO objects really support the operations the pair will perform on them.
Source
Thrown at Lib/_pyio.py:1375
reader and writer are RawIOBase objects that are readable and
writeable respectively. If the buffer_size is omitted it defaults to
DEFAULT_BUFFER_SIZE.
"""
# XXX The usefulness of this (compared to having two separate IO
# objects) is questionable.
def __init__(self, reader, writer, buffer_size=DEFAULT_BUFFER_SIZE):
"""Constructor.
The arguments are two RawIO instances.
"""
if not reader.readable():
raise OSError('"reader" argument must be readable.')
if not writer.writable():
raise OSError('"writer" argument must be writable.')
self.reader = BufferedReader(reader, buffer_size)
self.writer = BufferedWriter(writer, buffer_size)
def read(self, size=-1):
if size is None:
size = -1
return self.reader.read(size)
def readinto(self, b):
return self.reader.readinto(b)
def write(self, b):
return self.writer.write(b)
def peek(self, size=0):
return self.reader.peek(size)
View on GitHub (pinned to bc6749cc3b)
Solutions
- Pass a genuinely writable object as the second argument (e.g. open(path,'wb') or a write-capable socket wrapper)
- Open the file with a write mode ('wb', 'ab', 'w+b') instead of 'rb'
- For custom raw IO classes, override writable() to return True when write() is implemented
Example fix
# before
pair = io.BufferedRWPair(sock_r, open('log.bin','rb')) # writer not writable -> OSError
# after
pair = io.BufferedRWPair(sock_r, open('log.bin','wb')) Defensive patterns
Strategy: type-guard
Validate before calling
def make_rwpair(reader, writer, buffer_size=8192):
import io
if not writer.writable():
raise OSError('writer argument must be writable')
return io.BufferedRWPair(reader, writer, buffer_size) Type guard
def is_writable_raw(obj):
return hasattr(obj, 'writable') and callable(obj.writable) and obj.writable() Try / catch
try:
pair = io.BufferedRWPair(r, w)
except OSError as e:
if 'writable' in str(e):
w = open(path, 'wb')
pair = io.BufferedRWPair(r, w)
else:
raise Prevention
- Open the writer side with a write mode ('wb','ab') by construction
- For custom raw classes, override writable() alongside write()
- Document which end is which when wrapping duplex transports like sockets
When it happens
Trigger: io.BufferedRWPair(reader, writer) where writer.writable() returns False, e.g. a read-only FileIO opened with 'r', a socket wrapper that is read-only/shut down for writing, or a custom raw class whose writable() defaults to False.
Common situations: Passing two read streams (e.g. both ends opened read-only) to simulate a bidirectional channel; custom RawIOBase subclasses where only readable() was overridden; using a closed or half-shutdown socket object as the writer side.
Related errors
- "reader" argument must be readable.
- "raw" argument must be readable.
- "raw" argument must be writable.
- write() returned incorrect number of bytes
- seek() returned invalid position
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/e9a38ed709d56c26.
Report an issue: GitHub.