python/cpython · error · ValueError
unsupported whence value
Error message
unsupported whence value
What it means
BytesIO.seek (Lib/_pyio.py:995) accepts exactly three whence values — 0 (SEEK_SET), 1 (SEEK_CUR), 2 (SEEK_END) — and raises ValueError('unsupported whence value') for anything else. The check happens after all position arithmetic branches fail, catching typos, out-of-range constants, and mistaken API conventions.
Source
Thrown at Lib/_pyio.py:995
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")
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")
View on GitHub (pinned to bc6749cc3b)
Solutions
- Use the named constants io.SEEK_SET / io.SEEK_CUR / io.SEEK_END (or os.SEEK_*) instead of raw ints.
- Validate whence at the boundary: `if whence not in (0, 1, 2): raise ValueError(...)` with your own message.
- Map any custom seek semantics to one of the three supported modes before calling seek().
Example fix
# before buf.seek(offset, whence=3) # typo / unsupported -> ValueError # after import io buf.seek(offset, io.SEEK_END) # named constant, self-documenting
Defensive patterns
Strategy: validation
Validate before calling
import io
VALID_WHENCE = (io.SEEK_SET, io.SEEK_CUR, io.SEEK_END)
if whence not in VALID_WHENCE:
raise ValueError(f'whence must be one of {VALID_WHENCE}, got {whence!r}')
buf.seek(pos, whence) Try / catch
try:
buf.seek(pos, whence)
except ValueError as e:
if 'unsupported whence' in str(e):
buf.seek(pos, io.SEEK_SET) # fall back to absolute with a logged warning
else:
raise Prevention
- Always pass io.SEEK_SET / io.SEEK_CUR / io.SEEK_END instead of raw ints.
- Validate whence fields from protocols/user input against (0, 1, 2) at the boundary.
- Do not assume lseek extensions (SEEK_DATA, SEEK_HOLE) exist in Python's io layer.
When it happens
Trigger: buf.seek(0, 3) or buf.seek(0, -1); passing an unmapped enum/int constant (e.g. a custom SEEK-specific value or os.SEEK_HOLE/SEEK_DATA unsupported here); forwarding a whence from user input without validation.
Common situations: Confusing this API with C's lseek extensions (SEEK_DATA/SEEK_HOLE on Solaris/Linux); typos like whence=1 vs intended 2; protocol fields encoding whence as arbitrary ints.
Related errors
- negative seek position %r
- seek on closed file
- __getstate__ on closed file
- getvalue on closed file
- getbuffer on closed file
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/0079059b380189b9.
Report an issue: GitHub.