python/cpython · error · ValueError
seek on closed file
Error message
seek on closed file
What it means
BytesIO.seek (Lib/_pyio.py:977) begins with a closed-stream check and raises ValueError('seek on closed file'). The position bookkeeping still exists after close(), but the data is gone, so seeking is rejected to prevent a successful-looking seek followed by an empty read.
Source
Thrown at Lib/_pyio.py:977
if self.closed:
raise ValueError("write to closed file")
n = view.nbytes # Size of any bytes-like object
if n == 0:
return 0
with self._lock:
pos = self._pos
if pos > len(self._buffer):
# Pad buffer to pos with null bytes.
self._buffer.resize(pos)
self._buffer[pos:pos + n] = view
self._pos += n
return n
def seek(self, pos, whence=0):
if self.closed:
raise ValueError("seek on closed file")
try:
pos_index = pos.__index__
except AttributeError:
raise TypeError(f"{pos!r} is not an integer")
else:
pos = pos_index()
if whence == 0:
if pos < 0:
raise ValueError("negative seek position %r" % (pos,))
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")View on GitHub (pinned to bc6749cc3b)
Solutions
- Call seek() while the stream is open; move close() after the final re-read.
- Drop the explicit close() — BytesIO needs no deterministic cleanup.
- For repeated passes over the data, either keep the bytes (`data = buf.getvalue()`) and slice them, or reopen a fresh BytesIO(data).
Example fix
# before buf = io.BytesIO(payload) parse(buf) buf.close() buf.seek(0) # ValueError: seek on closed file # after buf = io.BytesIO(payload) parse(buf) buf.seek(0) # rewind while open parse2(buf) buf.close() # close last (or omit)
Defensive patterns
Strategy: validation
Validate before calling
def rewind(buf: io.BytesIO):
if buf.closed:
raise ValueError('BytesIO closed; seek before close')
buf.seek(0) Type guard
def is_open_bytesio(v) -> bool:
return isinstance(v, io.BytesIO) and not v.closed Try / catch
try:
buf.seek(0)
except ValueError as e:
if 'closed file' in str(e):
buf = io.BytesIO(original_bytes) # reopen from retained data
else:
raise Prevention
- Rewind (seek(0)) while the stream is open; close only after the last pass.
- For multi-pass parsing, retain data = buf.getvalue() and slice bytes instead of re-seeking.
- Do not close BytesIO in producer/first-pass code when consumers re-seek.
When it happens
Trigger: buf.seek(0) after buf.close(); rewinding a BytesIO to re-parse it after a cleanup path closed it; seek() issued by a retry loop after an earlier attempt closed the buffer.
Common situations: Parse-then-reparse flows (seek(0) before a second pass) where the first pass's error handling closed the buffer; BytesIO used as a scratch file in code ported from real-file logic with explicit close.
Related errors
- __getstate__ on closed file
- getvalue on closed file
- getbuffer on closed file
- read from closed file
- write to closed file
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/94831e39f9dfa967.
Report an issue: GitHub.