python/cpython · error · ValueError

truncate on closed file

Error message

truncate on closed file

What it means

Raised by BytesIO.truncate() when called on a stream that is already closed. truncate() would otherwise shrink the in-memory buffer to the given position (defaulting to the current position), but the guard 'if self.closed' rejects the operation up front. Like all closed-stream errors in _pyio it is a ValueError.

Source

Thrown at Lib/_pyio.py:1012

        else:
            raise ValueError("unsupported whence value")
        return self._pos

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

    def peek(self, size=0):
        if self.closed:
            raise ValueError("peek on closed file")
        if size < 1:
            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:

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Call truncate() before close(), typically right after finishing writes.
  2. Check 'if not bio.closed:' before truncating.
  3. Restructure so the with-block body contains both the writes and the truncate.

Example fix

# before
with io.BytesIO() as buf:
    buf.write(b"hello")
buf.truncate(2)  # ValueError: closed

# after
with io.BytesIO() as buf:
    buf.write(b"hello")
    buf.truncate(2)
Defensive patterns

Strategy: validation

Validate before calling

if not buf.closed:
    buf.truncate(target_len)

Try / catch

try:
    buf.truncate(target_len)
except ValueError as e:
    if "closed" in str(e):
        log.warning("skip truncate: stream already closed")
    else:
        raise

Prevention

When it happens

Trigger: Calling bio.truncate() or bio.truncate(n) on a BytesIO after bio.close(); commonly hit when truncate is called in a finally/except path after the file was already closed.

Common situations: Cleanup handlers that truncate 'to commit what was written' after closing; retry logic that truncates on failure but the stream was closed by a prior error; double-close followed by truncate.

Related errors


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