{"record":{"id":"318fae7eec63128d","repo":"RustPython/RustPython","slug":"seek-returned-an-invalid-position","errorCode":null,"errorMessage":"seek() returned an invalid position","messagePattern":"seek\\(\\) returned an invalid position","errorType":"exception","errorClass":"OSError","httpStatus":null,"severity":"error","filePath":"Lib/_pyio.py","lineNumber":782,"sourceCode":"\nclass _BufferedIOMixin(BufferedIOBase):\n\n    \"\"\"A mixin implementation of BufferedIOBase with an underlying raw stream.\n\n    This passes most requests on to the underlying raw stream.  It\n    does *not* provide implementations of read(), readinto() or\n    write().\n    \"\"\"\n\n    def __init__(self, raw):\n        self._raw = raw\n\n    ### Positioning ###\n\n    def seek(self, pos, whence=0):\n        new_position = self.raw.seek(pos, whence)\n        if new_position < 0:\n            raise OSError(\"seek() returned an invalid position\")\n        return new_position\n\n    def tell(self):\n        pos = self.raw.tell()\n        if pos < 0:\n            raise OSError(\"tell() returned an invalid position\")\n        return pos\n\n    def truncate(self, pos=None):\n        self._checkClosed()\n        self._checkWritable()\n\n        # Flush the stream.  We're mixing buffered I/O with lower-level I/O,\n        # and a flush may be necessary to synch both views of the current\n        # file state.\n        self.flush()\n\n        if pos is None:","sourceCodeStart":764,"sourceCodeEnd":800,"githubUrl":"https://github.com/RustPython/RustPython/blob/aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd/Lib/_pyio.py#L764-L800","documentation":"Raised by _pyio.BufferedIOBase.seek (Lib/_pyio.py:782) when the wrapped raw stream's seek() returns a negative new position. The buffered layer delegates to raw.seek(pos, whence) and requires the raw object to return the new absolute offset as a non-negative int; a negative return means the underlying stream broke the RawIOBase contract (e.g. a custom subclass returning -1 in C style for failure). It surfaces as a plain OSError with no errno, so it signals a broken raw stream rather than a normal OS-level seek error.","triggerScenarios":"Calling seek() on any buffered wrapper (open(path,'rb'), BufferedReader, BufferedWriter) whose raw layer is a user-defined io.RawIOBase subclass whose seek() returns -1; adapters over sockets/pipes or custom block devices that fake seekability; test mocks where seek is stubbed as lambda p, w: -1.","commonSituations":"Porting C code where lseek-style helpers return -1 on error; wrapping non-seekable transports (network streams, compressed sources) in a class that claims to seek; unit tests with over-simplified raw-stream doubles; third-party storage adapters implementing RawIOBase incorrectly.","solutions":["Fix the raw stream's seek() to return the new absolute position (>= 0), e.g. return os.lseek(self.fd, pos, whence), instead of -1","Have the custom raw seek() raise OSError itself on failure instead of returning a sentinel","Check raw.seekable() before calling buffered seek() so non-seekable streams are never asked for a position","Add a unit test asserting the custom seek() return value satisfies ret >= 0"],"exampleFix":"// before\nclass MyRaw(io.RawIOBase):\n    def seek(self, pos, whence=io.SEEK_SET):\n        os.lseek(self.fd, pos, whence)\n        return -1  # C-style error sentinel\n\nbuf = io.BufferedReader(MyRaw())\nbuf.seek(0)  # OSError: seek() returned an invalid position\n\n// after\nclass MyRaw(io.RawIOBase):\n    def seek(self, pos, whence=io.SEEK_SET):\n        return os.lseek(self.fd, pos, whence)\n\nbuf.seek(0)","handlingStrategy":"try-catch","validationCode":"pos = raw.seek(0, io.SEEK_CUR)\nif not isinstance(pos, int) or pos < 0:\n    raise RuntimeError(\"raw stream seek() contract violated: %r\" % (pos,))","typeGuard":"def valid_raw_seek_result(ret) -> bool:\n    return isinstance(ret, int) and ret >= 0","tryCatchPattern":"try:\n    f.seek(offset, whence)\nexcept OSError as e:\n    if e.args == (\"seek() returned an invalid position\",):\n        # raw stream broke the seek() contract — fix its implementation\n        raise\n    raise","preventionTips":["Raw seek() implementations must return the new absolute offset, never -1","Raise OSError inside the raw stream on real failures instead of returning sentinels","Unit-test custom RawIOBase.seek with self.assertGreaterEqual(ret, 0)"],"tags":["python","io","buffered-io","seek","raw-stream","rawiobase"],"backgroundTag":"invalid-stream-position","analyzedSha":"aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd","analyzedAt":"2026-08-17T00:37:52.100Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}