python/cpython · error · OSError

seek() returned an invalid position

Error message

seek() returned an invalid position

What it means

BufferedRaw.seek (Lib/_pyio.py:782) delegates to the underlying raw stream's seek(pos, whence) and validates the result: a seek must return the new absolute position, which can never be negative. If the raw object returns a negative number, the buffered layer raises a plain OSError because the raw stream is broken or misimplemented.

Source

Thrown at Lib/_pyio.py:782

class _BufferedIOMixin(BufferedIOBase):

    """A mixin implementation of BufferedIOBase with an underlying raw stream.

    This passes most requests on to the underlying raw stream.  It
    does *not* provide implementations of read(), readinto() or
    write().
    """

    def __init__(self, raw):
        self._raw = raw

    ### Positioning ###

    def seek(self, pos, whence=0):
        new_position = self.raw.seek(pos, whence)
        if new_position < 0:
            raise OSError("seek() returned an invalid position")
        return new_position

    def tell(self):
        pos = self.raw.tell()
        if pos < 0:
            raise OSError("tell() returned an invalid position")
        return pos

    def truncate(self, pos=None):
        self._checkClosed()
        self._checkWritable()

        # Flush the stream.  We're mixing buffered I/O with lower-level I/O,
        # and a flush may be necessary to synch both views of the current
        # file state.
        self.flush()

        if pos is None:

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Fix the custom raw seek() to return the new absolute position (a non-negative int) on success.
  2. On failure, raise OSError from the raw seek() instead of returning a sentinel like -1.
  3. If the underlying object is not seekable, return 0-style identity or raise OSError(ESPIPE) from seekable() checks, and have callers honor seekable() before calling seek().

Example fix

# before
class MyRaw(io.RawIOBase):
    def seek(self, pos, whence=0):
        if whence != 0:
            return -1  # -> OSError: seek() returned an invalid position
        self._off = pos
        return self._off

# after
class MyRaw(io.RawIOBase):
    def seek(self, pos, whence=0):
        if whence != 0:
            raise OSError('unsupported whence')
        self._off = pos
        return self._off  # always a non-negative absolute position
Defensive patterns

Strategy: validation

Validate before calling

if not f.seekable():
    raise OSError('stream is not seekable')
new_pos = f.seek(pos, whence)  # raw layer validates the returned position

Try / catch

try:
    f.seek(0)
except OSError as e:
    if 'invalid position' in str(e):
        # underlying raw stream is broken; cannot recover transparently
        raise
    raise

Prevention

When it happens

Trigger: A custom raw stream whose seek() returns -1 on failure (a C-convention errno style) instead of raising; seek() returning the whence-relative offset or an uninitialized variable; wrapping a device or socket-like object in a buffered reader without a real seek.

Common situations: Porting C library wrappers that use -1 sentinel returns; mocking raw.seek in tests to return -1; implementing file-like adapters over pipes or sockets where seek is meaningless but implemented anyway.

Related errors


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