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

  1. Check capabilities first: stream.seekable(), stream.readable(), stream.writable() (or hasattr) before invoking optional operations.
  2. If you own the subclass, implement the missing method (or inherit from a richer base: io.RawIOBase instead of io.IOBase).
  3. Catch io.UnsupportedOperation (note it is both OSError and ValueError) at the boundary where stream types vary.
  4. 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

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


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