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.

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.

Appendix: 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)