python/cpython · error · ValueError

invalid whence value

Error message

invalid whence value

What it means

Raised by BufferedReader.seek(pos, whence) when whence is not in valid_seek_flags (0/SEEK_SET, 1/SEEK_CUR, 2/SEEK_END in the stdlib set). The check runs before the closed-file check, so even a closed reader complains about whence first. ValueError('invalid whence value').

Source

Thrown at Lib/_pyio.py:1236

                # Otherwise refill internal buffer - unless we're
                # in read1 mode and already got some data
                elif not (read1 and written):
                    if not self._peek_unlocked(1):
                        break # eof

                # In readinto1 mode, return as soon as we have some data
                if read1 and written:
                    break

        return written

    def tell(self):
        # GH-95782: Keep return value non-negative
        return max(_BufferedIOMixin.tell(self) - len(self._read_buf) + self._read_pos, 0)

    def seek(self, pos, whence=0):
        if whence not in valid_seek_flags:
            raise ValueError("invalid whence value")
        self._checkClosed("seek of closed file")
        with self._read_lock:
            if whence == 1:
                pos -= len(self._read_buf) - self._read_pos
            pos = _BufferedIOMixin.seek(self, pos, whence)
            self._reset_read_buf()
            return pos

class BufferedWriter(_BufferedIOMixin):

    """A buffer for a writeable sequential RawIO object.

    The constructor creates a BufferedWriter for the given writeable raw
    stream. If the buffer_size is not given, it defaults to
    DEFAULT_BUFFER_SIZE.
    """

    def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE):

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Pass whence as one of os.SEEK_SET / os.SEEK_CUR / os.SEEK_END (0, 1, 2).
  2. Verify argument order: seek(offset, whence).
  3. Map/validate external whence codes to the standard constants before calling seek.

Example fix

# before
reader.seek(os.SEEK_SET, 10)  # args swapped -> whence=0 pos... actually invalid

# after
reader.seek(10, os.SEEK_SET)
Defensive patterns

Strategy: validation

Validate before calling

import os
assert whence in (os.SEEK_SET, os.SEEK_CUR, os.SEEK_END)
reader.seek(pos, whence)

Type guard

def valid_whence(w) -> bool:
    import os
    return w in (os.SEEK_SET, os.SEEK_CUR, os.SEEK_END)

Try / catch

try:
    reader.seek(pos, whence)
except ValueError as e:
    if "whence" in str(e):
        reader.seek(pos, os.SEEK_SET)  # or raise with caller context
    else:
        raise

Prevention

When it happens

Trigger: reader.seek(0, 3), reader.seek(0, -1), or forwarding a whence obtained from another API whose enum differs; also passing the arguments swapped: seek(0, pos) makes the position land in the whence slot.

Common situations: Argument-order mistakes (seek(offset, whence) vs seek(whence, offset)); using non-constant sentinel values (e.g. os.SEEK_ constants vs homemade 3=SEEK_DATA on a reader that does not accept it); forwarding user input without validation.

Related errors


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