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

  1. Always use the named constants io.SeekStart, io.SeekCurrent, io.SeekEnd instead of raw 0/1/2.
  2. Validate whence is in {0,1,2} before calling Seek if the value originates from external/untrusted input.
  3. If porting from C-style APIs, map SEEK_SET/CUR/END to the io constants explicitly.
  4. 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

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


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/09c18428d57f499a. Report an issue: GitHub.