python/cpython · error · UnsupportedOperation
%s.%s() not supported
Error message
%s.%s() not supported
What it means
Raised by IOBase._unsupported() as io.UnsupportedOperation (a subclass of both OSError and ValueError) when a stream method is called that the concrete stream class deliberately does not implement. Base/raw classes stub out methods like read, write, truncate, fileno with this generic '%s.%s() not supported' message naming the class and method.
Source
Thrown at Lib/_pyio.py:343
Note that calling any method (even inquiries) on a closed stream is
undefined. Implementations may raise OSError in this case.
IOBase (and its subclasses) support the iterator protocol, meaning
that an IOBase object can be iterated over yielding the lines in a
stream.
IOBase also supports the :keyword:`with` statement. In this example,
fp is closed after the suite of the with statement is complete:
with open('spam.txt', 'r') as fp:
fp.write('Spam and eggs!')
"""
### Internal ###
def _unsupported(self, name):
"""Internal: raise an OSError exception for unsupported operations."""
raise UnsupportedOperation("%s.%s() not supported" %
(self.__class__.__name__, name))
### Positioning ###
def seek(self, pos, whence=0):
"""Change stream position.
Change the stream position to byte offset pos. Argument pos is
interpreted relative to the position indicated by whence. Values
for whence are ints:
* 0 -- start of stream (the default); offset should be zero or
positive
* 1 -- current stream position; offset may be negative
* 2 -- end of stream; offset is usually negative
Some operating systems / file systems could provide additional
values.
View on GitHub (pinned to bc6749cc3b)
Solutions
- Check capabilities first: stream.seekable(), stream.readable(), stream.writable() (or hasattr) before invoking optional operations.
- If you own the subclass, implement the missing method (or inherit from a richer base: io.RawIOBase instead of io.IOBase).
- Catch io.UnsupportedOperation (note it is both OSError and ValueError) at the boundary where stream types vary.
- Pass appropriately-wrapped streams (e.g. BufferedReader over a raw object) rather than raw stubs.
Example fix
// before
data = stream.read(4096) # UnsupportedOperation: RawIOBase-like stub
// after
if stream.readable():
data = stream.read(4096)
else:
data = None Defensive patterns
Strategy: type-guard
Validate before calling
ops = {'read': getattr(stream, 'readable', None),
'write': getattr(stream, 'writable', None),
'seek': getattr(stream, 'seekable', None)}
for name, probe in ops.items():
if probe and probe():
pass # capability available; safe to call the corresponding method Type guard
def supports(stream, op: str) -> bool:
probe = {'read': 'readable', 'write': 'writable', 'seek': 'seekable'}[op]
fn = getattr(stream, probe, None)
return callable(fn) and fn() Try / catch
import io
try:
stream.truncate()
except io.UnsupportedOperation:
pass # this stream class does not implement truncate() Prevention
- Probe with readable()/writable()/seekable() instead of calling and catching.
- When subclassing IOBase, override every operation your API contract promises.
- Prefer composing io.BufferedReader/Writer over raw stubs when passing streams to stdlib consumers.
When it happens
Trigger: io.RawIOBase().read(10); calling .truncate() on a socket wrapper that did not override it; .fileno() on classes like io.BytesIO subclasses that inherit the unsupported stub; calling .write() on a read-only custom raw stream that never overrode write(). Also subprocess/pipe-based streams missing seek.
Common situations: Writing custom IOBase subclasses and forgetting to override the operations you advertise; generic framework code that probes capabilities by calling methods (instead of checking seekable()/readable()/writable()); mixing stream types (passing a raw stream where buffered/text expected).
Related errors
- File or stream is not seekable.
- File or stream is not readable.
- File or stream is not writable.
- seek() returned an invalid position
- tell() returned an invalid position
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/b4f882baefda8c7d.
Report an issue: GitHub.