RustPython/RustPython · error · ValueError

negative truncate position %r

Error message

negative truncate position %r

What it means

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.

Source

Thrown at Lib/_pyio.py:999

    def tell(self):
        if self.closed:
            raise ValueError("tell on closed file")
        return self._pos

    def truncate(self, pos=None):
        if self.closed:
            raise ValueError("truncate on closed file")
        if pos is None:
            pos = self._pos
        else:
            try:
                pos_index = pos.__index__
            except AttributeError:
                raise TypeError(f"{pos!r} is not an integer")
            else:
                pos = pos_index()
            if pos < 0:
                raise ValueError("negative truncate position %r" % (pos,))
        del self._buffer[pos:]
        return pos

    def readable(self):
        if self.closed:
            raise ValueError("I/O operation on closed file.")
        return True

    def writable(self):
        if self.closed:
            raise ValueError("I/O operation on closed file.")
        return True

    def seekable(self):
        if self.closed:
            raise ValueError("I/O operation on closed file.")
        return True

View on GitHub (pinned to aaeab4f754)

Solutions

  1. Clamp the argument: buf.truncate(max(0, pos))
  2. Omit the argument (or pass None) to truncate at the current position
  3. Recompute sizes defensively: new_size = max(0, len(buf) - extra)

Example fix

// before
buf.truncate(len(buf.getvalue()) - overhead)  # negative when overhead > size

// after
buf.truncate(max(0, len(buf.getvalue()) - overhead))
Defensive patterns

Strategy: validation

Validate before calling

buf.truncate(max(0, pos)) if pos is not None else buf.truncate()

Try / catch

try:
    buf.truncate(pos)
except ValueError as e:
    if "negative truncate position" in str(e):
        buf.truncate(0)
    else:
        raise

Prevention

When it happens

Trigger: buf.truncate(-1); buf.truncate(len(buf) - extra) where extra > len(buf); negative sizes computed by subtraction without clamping.

Common situations: 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.

Related errors


AI-assisted analysis of RustPython/RustPython@aaeab4f754 (2026-08-17). Data as JSON: /api/errors/db832648be91a0cb. Report an issue: GitHub.