python/cpython · error · UnsupportedOperation
File or stream is not seekable.
Error message
File or stream is not seekable.
What it means
Raised by IOBase._checkSeekable() as io.UnsupportedOperation when seek(), tell(), or truncate() is called on a stream whose seekable() returns False. Non-seekable streams are sequential-only OS channels — pipes, sockets, terminal input — where a position does not exist, so random access is refused.
Source
Thrown at Lib/_pyio.py:434
# If close() fails, the caller logs the exception with
# sys.unraisablehook. close() must be called at the end at __del__().
self.close()
### Inquiries ###
def seekable(self):
"""Return a bool indicating whether object supports random access.
If False, seek(), tell() and truncate() will raise OSError.
This method may need to do a test seek().
"""
return False
def _checkSeekable(self, msg=None):
"""Internal: raise UnsupportedOperation if file is not seekable
"""
if not self.seekable():
raise UnsupportedOperation("File or stream is not seekable."
if msg is None else msg)
def readable(self):
"""Return a bool indicating whether object was opened for reading.
If False, read() will raise OSError.
"""
return False
def _checkReadable(self, msg=None):
"""Internal: raise UnsupportedOperation if file is not readable
"""
if not self.readable():
raise UnsupportedOperation("File or stream is not readable."
if msg is None else msg)
def writable(self):
"""Return a bool indicating whether object was opened for writing.View on GitHub (pinned to bc6749cc3b)
Solutions
- Guard with if stream.seekable(): before seek/tell/truncate.
- For stdin re-reading, buffer the content first: data = sys.stdin.buffer.read(), then parse from memory (io.BytesIO(data) is seekable).
- Restructure one-pass: single-pass parsing instead of seek-back rereads.
- Catch io.UnsupportedOperation where stream provenance varies (file vs pipe).
Example fix
// before sys.stdin.seek(0) # UnsupportedOperation on a pipe lines2 = sys.stdin.readlines() // after data = sys.stdin.buffer.read() # one full pass import io stream = io.BytesIO(data) # seekable in-memory copy lines2 = stream.readlines()
Defensive patterns
Strategy: type-guard
Validate before calling
if stream.seekable():
stream.seek(0)
payload = stream.read()
else:
payload = stream.read() # single pass; no rewind possible Type guard
def is_seekable(stream) -> bool:
probe = getattr(stream, 'seekable', None)
return callable(probe) and probe() Try / catch
import io
try:
stream.seek(0)
except io.UnsupportedOperation:
stream = io.BytesIO(original_bytes) # fallback: seekable in-memory copy Prevention
- Write one-pass parsers; do not rely on seek(0) to re-read stdin/pipes.
- Buffer stdin fully (sys.stdin.buffer.read()) when you need random access, then wrap in io.BytesIO.
- Test file-handling code with a pipe (cmd | python x.py) to catch seek assumptions early.
When it happens
Trigger: sys.stdin.seek(0); f.seek(0) where f wraps a pipe (e.g. output of subprocess.Popen(..., stdout=PIPE)); gzip/bz2 modules or fileinput probing the underlying stream; calling .tell() on a socket makefile() object; code that re-reads input by seeking back to position 0.
Common situations: Scripts that work on regular files and then get a pipe redirected in (cmd | script) — the seek(0)-to-reread pattern breaks; stdin re-reading in interactive tools; feeding subprocess pipes into parsers that expect random access; HTTP chunked uploads trying to seek a streamed body.
Related errors
- %s.%s() not supported
- File or stream is not readable.
- File or stream is not writable.
- seek() returned an invalid position
- seek on closed file
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/a29d0deaa771cc55.
Report an issue: GitHub.