golang/go · error
bytes.Reader.Seek: negative position
Error message
bytes.Reader.Seek: negative position
What it means
bytes.Reader.Seek returns this error when the computed absolute position would be negative (reader.go:129-131). After resolving offset against whence (start/current/end), the resulting position must be >= 0; a negative position is impossible for a forward-only byte slice, so the Reader rejects it. prevRune has already been cleared by this point.
Source
Thrown at src/bytes/reader.go:130
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")
}
r.i += int64(m)
n = int64(m)View on GitHub (pinned to b6b368adc5)
Solutions
- Clamp the computed absolute position to >= 0 before calling Seek, or compute offset so abs cannot go negative.
- For relative backward seeks, check the current position (via a prior Seek(0, io.SeekCurrent)) and bound n to it.
- Validate offsets originating from user input (HTTP Range, cursors) and reject negative start explicitly.
- Add a test for backward-seek edge cases near position 0.
Example fix
// before — backward seek can overshoot start
r.Seek(-n, io.SeekCurrent) // negative position if n > pos
// after — bound n to the current position
cur, _ := r.Seek(0, io.SeekCurrent)
if n > cur { n = cur }
r.Seek(-n, io.SeekCurrent) Defensive patterns
Strategy: validation
Validate before calling
// Compute and validate the absolute position before Seek.
func safeSeek(r *bytes.Reader, off int64, whence int) (int64, error) {
var abs int64
switch whence {
case io.SeekStart: abs = off
case io.SeekCurrent:
cur, _ := r.Seek(0, io.SeekCurrent); abs = cur + off
case io.SeekEnd:
cur, _ := r.Seek(0, io.SeekEnd); abs = cur + off
}
if abs < 0 {
return 0, fmt.Errorf("seek to negative position %d", abs)
}
return r.Seek(off, whence)
} Try / catch
pos, err := r.Seek(off, whence)
if err != nil && strings.Contains(err.Error(), "negative position") {
// clamp off or bound backward seeks
} Prevention
- Clamp computed absolute positions to >= 0 before Seek.
- For backward relative seeks, bound n to the current position.
- Validate offsets from user input (Range, cursors) and reject negatives explicitly.
When it happens
Trigger: Triggered when abs < 0 after the whence computation: e.g., Seek(-5, io.SeekStart), Seek(-100, io.SeekCurrent) when fewer than 100 bytes have been read, or Seek(-N, io.SeekEnd) where N exceeds the slice length (reader.go:120-130).
Common situations: A relative backward seek (Seek(-n, io.SeekCurrent)) that overshoots the start. Computing an offset from a length that turns out larger than expected. Negative offsets passed through from Range headers or pagination cursors without clamping.
Related errors
- bytes.Reader.Seek: invalid whence
- 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/da9c4bbb0b6d47c2.
Report an issue: GitHub.