{"record":{"id":"db832648be91a0cb","repo":"RustPython/RustPython","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":999,"sourceCode":"    def tell(self):\n        if self.closed:\n            raise ValueError(\"tell on closed file\")\n        return self._pos\n\n    def truncate(self, pos=None):\n        if self.closed:\n            raise ValueError(\"truncate on closed file\")\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":981,"sourceCodeEnd":1017,"githubUrl":"https://github.com/RustPython/RustPython/blob/aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd/Lib/_pyio.py#L981-L1017","documentation":"BytesIO.truncate (Lib/_pyio.py:999) raises ValueError('negative truncate position %r' % (pos,)) when an explicitly passed pos is negative after integer coercion. truncate(None) uses the current position and never fails this check; only an explicit negative size does, because an in-memory buffer cannot have a negative length. OS files would fail with EINVAL at the ftruncate level; BytesIO enforces the same rule in Python.","triggerScenarios":"buf.truncate(-1); buf.truncate(len(buf) - extra) where extra > len(buf); negative sizes computed by subtraction without clamping.","commonSituations":"Size-cap code that subtracts an overhead/allowance from the current length; ported file-ftruncate logic; input-derived sizes that can go negative on malformed data.","solutions":["Clamp the argument: buf.truncate(max(0, pos))","Omit the argument (or pass None) to truncate at the current position","Recompute sizes defensively: new_size = max(0, len(buf) - extra)"],"exampleFix":"// before\nbuf.truncate(len(buf.getvalue()) - overhead)  # negative when overhead > size\n\n// after\nbuf.truncate(max(0, len(buf.getvalue()) - overhead))","handlingStrategy":"validation","validationCode":"buf.truncate(max(0, pos)) if pos is not None else buf.truncate()","typeGuard":null,"tryCatchPattern":"try:\n    buf.truncate(pos)\nexcept ValueError as e:\n    if \"negative truncate position\" in str(e):\n        buf.truncate(0)\n    else:\n        raise","preventionTips":["Clamp computed sizes with max(0, ...)","Pass None (or nothing) to truncate at the current position","Treat negative sizes from user input as validation errors, not seek targets"],"tags":["python","io","bytesio","truncate","negative-position"],"backgroundTag":"negative-truncate-position","analyzedSha":"aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd","analyzedAt":"2026-08-17T00:37:52.100Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}