golang/go · error
bytes.Reader.Seek: invalid whence
Error message
bytes.Reader.Seek: invalid whence
What it means
bytes.Reader.Seek returns this error when the whence argument is not one of io.SeekStart (0), io.SeekCurrent (1), or io.SeekEnd (2) (reader.go:126-128, the default branch). The whence parameter selects how the offset is interpreted; an unrecognized value has no defined semantics, so the Reader rejects it before touching position. Note Seek clears prevRune regardless.
Source
Thrown at src/bytes/reader.go:127
}
r.i = int64(r.prevRune)
r.prevRune = -1
return nil
}
// Seek implements the [io.Seeker] interface.
func (r *Reader) Seek(offset int64, whence int) (int64, error) {
r.prevRune = -1
var abs int64
switch whence {
case io.SeekStart:
abs = offset
case io.SeekCurrent:
abs = r.i + offset
case io.SeekEnd:
abs = int64(len(r.s)) + offset
default:
return 0, errors.New("bytes.Reader.Seek: invalid whence")
}
if abs < 0 {
return 0, errors.New("bytes.Reader.Seek: negative position")
}
r.i = abs
return abs, nil
}
// WriteTo implements the [io.WriterTo] interface.
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
r.prevRune = -1
if r.i >= int64(len(r.s)) {
return 0, nil
}
b := r.s[r.i:]
m, err := w.Write(b)
if m > len(b) {
panic("bytes.Reader.WriteTo: invalid Write count")View on GitHub (pinned to b6b368adc5)
Solutions
- Always use the named constants io.SeekStart, io.SeekCurrent, io.SeekEnd instead of raw 0/1/2.
- Validate whence is in {0,1,2} before calling Seek if the value originates from external/untrusted input.
- If porting from C-style APIs, map SEEK_SET/CUR/END to the io constants explicitly.
- Add a test that asserts Seek is only called with the three valid whence values.
Example fix
// before — raw or wrong whence constant r.Seek(10, 3) // invalid whence // after — use the io constant r.Seek(10, io.SeekStart) // or io.SeekCurrent / io.SeekEnd
Defensive patterns
Strategy: validation
Validate before calling
// Validate whence against the io constants before Seek.
func safeSeek(r *bytes.Reader, off int64, whence int) (int64, error) {
switch whence {
case io.SeekStart, io.SeekCurrent, io.SeekEnd:
default:
return 0, fmt.Errorf("invalid whence %d", whence)
}
return r.Seek(off, whence)
} Try / catch
pos, err := r.Seek(off, whence)
if err != nil && strings.Contains(err.Error(), "invalid whence") {
// whence was not 0/1/2; fix the caller
} Prevention
- Always use io.SeekStart, io.SeekCurrent, io.SeekEnd — never raw integers.
- Validate whence if it originates from external input.
- Map C-style SEEK_* constants to the io package constants when porting.
When it happens
Trigger: Triggered by reader.Seek(offset, whence) where whence is any value other than 0, 1, or 2 (reader.go:119-128). Typically a typo'd constant, an uninitialized variable, or a value passed through from an upstream API that uses a different whence convention.
Common situations: Passing a raw integer instead of the io.Seek* constant. Mixing OS-level SEEK_SET/SEEK_CUR/SEEK_END constants (which happen to be 0/1/2 but are conceptually different) without mapping. A whence variable that was declared but never assigned (defaults to 0, but computed whence expressions can yield other values).
Related errors
- bytes.Reader.Seek: negative position
- bytes.Reader.ReadAt: negative offset
- bytes.Reader.UnreadByte: at beginning of slice
- bytes.Reader.UnreadRune: at beginning of slice
- bytes.Reader.UnreadRune: previous operation was not ReadRune
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/09c18428d57f499a.
Report an issue: GitHub.