python/cpython · error · ValueError

negative truncate position %r

Error message

negative truncate position %r

What it means

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.

Source

Thrown at Lib/_pyio.py:1025

            return self._buffer[self._pos:self._pos + io.DEFAULT_BUFFER_SIZE]
        return self._buffer[self._pos:self._pos + size]

    def truncate(self, pos=None):
        if self.closed:
            raise ValueError("truncate on closed file")

        with self._lock:
            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 bc6749cc3b)

Solutions

  1. Clamp the position: buf.truncate(max(0, pos)).
  2. Fix the arithmetic so the computed offset cannot be negative (use max(size - n, 0)).
  3. Validate user-supplied lengths against 0 <= pos before calling truncate.

Example fix

# before
buf.truncate(buf.tell() - n)  # negative when n > tell()

# after
buf.truncate(max(0, buf.tell() - n))
Defensive patterns

Strategy: validation

Validate before calling

pos = max(0, int(pos))
buf.truncate(pos)

Try / catch

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

Prevention

When it happens

Trigger: 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).

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

Related errors


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