python/cpython · error · ValueError
tell on closed file
Error message
tell on closed file
What it means
BytesIO.tell (Lib/_pyio.py:1000) returns the current absolute position self._pos, but first checks the closed flag and raises ValueError('tell on closed file'). After close() the buffer contents are gone even though the position variable survives, so reporting a position for a dead stream is treated as an error.
Source
Thrown at Lib/_pyio.py:1000
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")
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:View on GitHub (pinned to bc6749cc3b)
Solutions
- Capture the position before closing: `pos = buf.tell()` then `buf.close()`.
- Remove premature close() calls; BytesIO requires no deterministic cleanup.
- In finally blocks, guard with `if not buf.closed: log(buf.tell())`.
Example fix
# before
buf = io.BytesIO(data)
consume(buf)
buf.close()
log('consumed up to %d', buf.tell()) # ValueError
# after
buf = io.BytesIO(data)
consume(buf)
log('consumed up to %d', buf.tell()) # capture while open
buf.close() # close last (or omit) Defensive patterns
Strategy: validation
Validate before calling
def position_of(buf: io.BytesIO) -> int:
if buf.closed:
raise ValueError('BytesIO closed; call tell() before close')
return buf.tell() Type guard
def is_open_bytesio(v) -> bool:
return isinstance(v, io.BytesIO) and not v.closed Try / catch
try:
pos = buf.tell()
except ValueError as e:
if 'closed file' in str(e):
pos = -1 # position unreportable after close
else:
raise Prevention
- Capture tell() before close() when logging consumed offsets.
- Guard tell() in finally blocks with `if not buf.closed:`.
- Avoid explicit close() on BytesIO; let it go out of scope.
When it happens
Trigger: buf.tell() after buf.close(); logging or asserting the read offset after cleanup closed the buffer; calling tell() in a finally block that runs after an explicit close in the error path.
Common situations: Progress logging in parsers that close on EOF and then report bytes consumed; debug code calling tell() on streams managed by a context manager that already exited.
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/8af507ff3418ab99.
Report an issue: GitHub.