python/cpython · error · ValueError

peek on closed file

Error message

peek on closed file

What it means

Raised by BytesIO.peek() in Python's pure-Python io module when the stream has already been closed. peek() tries to look ahead into the in-memory buffer without consuming it, but a closed BytesIO has been released and no I/O is permitted. It is a ValueError raised eagerly before any buffer slicing occurs.

Source

Thrown at Lib/_pyio.py:1005

            self._pos = pos
        elif whence == 1:
            with self._lock:
                self._pos = max(0, self._pos + pos)
        elif whence == 2:
            with self._lock:
                self._pos = max(0, len(self._buffer) + pos)
        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()

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Ensure peek() is called before close() / before the 'with' block exits.
  2. Guard the call with 'if not bio.closed:' before peeking.
  3. If late inspection is intended, keep the raw bytes separately (e.g. getvalue() before closing) instead of peeking a closed stream.

Example fix

// before
buf = io.BytesIO(b"data")
buf.close()
buf.peek(2)  # ValueError

// after
buf = io.BytesIO(b"data")
head = buf.peek(2)
buf.close()
Defensive patterns

Strategy: validation

Validate before calling

if not buf.closed:
    head = buf.peek(4)
else:
    head = b""  # stream finished

Try / catch

try:
    head = buf.peek(4)
except ValueError as e:
    if "closed" in str(e):
        raise RuntimeError("stream closed before peek") from e
    raise

Prevention

When it happens

Trigger: Calling bio.peek() (optionally with a size) on a BytesIO instance after bio.close() was called, e.g. peeking during cleanup code or after a with block exited.

Common situations: Peeking inside a 'with io.BytesIO(...) as f:' block after the block exited; reusing a BytesIO stored on an object whose close() lifecycle already ran; test teardown code that closes fixtures then inspects them.

Related errors


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