{"record":{"id":"0e21c10c15ba6640","repo":"python/cpython","slug":"negative-truncate-position-r","errorCode":null,"errorMessage":"negative truncate position %r","messagePattern":"negative truncate position %r","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pyio.py","lineNumber":1025,"sourceCode":"            return self._buffer[self._pos:self._pos + io.DEFAULT_BUFFER_SIZE]\n        return self._buffer[self._pos:self._pos + size]\n\n    def truncate(self, pos=None):\n        if self.closed:\n            raise ValueError(\"truncate on closed file\")\n\n        with self._lock:\n            if pos is None:\n                pos = self._pos\n            else:\n                try:\n                    pos_index = pos.__index__\n                except AttributeError:\n                    raise TypeError(f\"{pos!r} is not an integer\")\n                else:\n                    pos = pos_index()\n                if pos < 0:\n                    raise ValueError(\"negative truncate position %r\" % (pos,))\n            del self._buffer[pos:]\n        return pos\n\n    def readable(self):\n        if self.closed:\n            raise ValueError(\"I/O operation on closed file.\")\n        return True\n\n    def writable(self):\n        if self.closed:\n            raise ValueError(\"I/O operation on closed file.\")\n        return True\n\n    def seekable(self):\n        if self.closed:\n            raise ValueError(\"I/O operation on closed file.\")\n        return True\n","sourceCodeStart":1007,"sourceCodeEnd":1043,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyio.py#L1007-L1043","documentation":"Raised by BytesIO.truncate(pos) when the (already integer-converted) position is negative. After pos.__index__() succeeds, the check 'if pos < 0' rejects values below zero because a buffer cannot be truncated to a negative length. It is a ValueError whose message interpolates the offending position.","triggerScenarios":"Calling bio.truncate(-1) or passing any negative integer, including one produced by __index__ of a custom type or an arithmetic bug (e.g. subtracting too much: size - offset where offset > size).","commonSituations":"Offset arithmetic that goes negative (current_pos - rewind where rewind > pos); parsing user-supplied negative limits from CLI/config; sign errors when truncating to 'end minus N bytes'.","solutions":["Clamp the position: buf.truncate(max(0, pos)).","Fix the arithmetic so the computed offset cannot be negative (use max(size - n, 0)).","Validate user-supplied lengths against 0 <= pos before calling truncate."],"exampleFix":"# before\nbuf.truncate(buf.tell() - n)  # negative when n > tell()\n\n# after\nbuf.truncate(max(0, buf.tell() - n))","handlingStrategy":"validation","validationCode":"pos = max(0, int(pos))\nbuf.truncate(pos)","typeGuard":null,"tryCatchPattern":"try:\n    buf.truncate(pos)\nexcept ValueError as e:\n    if \"negative truncate\" in str(e):\n        buf.truncate(0)\n    else:\n        raise","preventionTips":["Clamp computed offsets with max(0, ...).","Validate 0 <= pos <= len(data) for user-supplied values.","Watch sign errors in 'end - n' style arithmetic."],"tags":["python","io","bytesio","truncate","valueerror","validation"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}