golang/go · error

bytes.Reader.ReadAt: negative offset

Error message

bytes.Reader.ReadAt: negative offset

What it means

bytes.Reader.ReadAt returns this error when the caller passes a negative offset (reader.go:52-54). ReadAt must not modify reader state, and a negative offset has no meaningful position; the Reader rejects it rather than reading from an undefined location. Unlike EOF (returned when off >= len(s)), this is a programmer error, not an end-of-data signal.

Source

Thrown at src/bytes/reader.go:53

// The result is unaffected by any method calls except [Reader.Reset].
func (r *Reader) Size() int64 { return int64(len(r.s)) }

// Read implements the [io.Reader] interface.
func (r *Reader) Read(b []byte) (n int, err error) {
	if r.i >= int64(len(r.s)) {
		return 0, io.EOF
	}
	r.prevRune = -1
	n = copy(b, r.s[r.i:])
	r.i += int64(n)
	return
}

// ReadAt implements the [io.ReaderAt] interface.
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
	// cannot modify state - see io.ReaderAt
	if off < 0 {
		return 0, errors.New("bytes.Reader.ReadAt: negative offset")
	}
	if off >= int64(len(r.s)) {
		return 0, io.EOF
	}
	n = copy(b, r.s[off:])
	if n < len(b) {
		err = io.EOF
	}
	return
}

// ReadByte implements the [io.ByteReader] interface.
func (r *Reader) ReadByte() (byte, error) {
	r.prevRune = -1
	if r.i >= int64(len(r.s)) {
		return 0, io.EOF
	}
	b := r.s[r.i]

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Validate off >= 0 before calling ReadAt; if a relative seek is intended, compute the absolute offset and clamp at 0.
  2. If off is derived from user input, sanitize it (max(0, off)) and surface a clear error to the caller.
  3. Switch to Reader.Seek + Read if you need relative positioning semantics instead of absolute ReadAt.
  4. Add an assertion/test that the offset passed to ReadAt is non-negative for all code paths.

Example fix

// before — off can be negative from subtraction
off := start - headerLen // negative if start < headerLen
n, err := r.ReadAt(buf, off)

// after — validate and clamp
if off < 0 {
    return 0, fmt.Errorf("invalid offset %d", off)
}
n, err := r.ReadAt(buf, off)
Defensive patterns

Strategy: validation

Validate before calling

// Validate offset before calling ReadAt.
func safeReadAt(r *bytes.Reader, p []byte, off int64) (int, error) {
    if off < 0 {
        return 0, fmt.Errorf("readat: negative offset %d", off)
    }
    return r.ReadAt(p, off)
}

Try / catch

n, err := r.ReadAt(p, off)
if err != nil && strings.Contains(err.Error(), "negative offset") {
    // off was negative; fix the upstream offset computation
}

Prevention

When it happens

Trigger: Triggered by reader.ReadAt(buf, off) where off < 0 (reader.go:52). Common when off is computed from a subtraction that underflows, or when an upstream caller passes through an unchecked negative value.

Common situations: Range requests with negative start offsets (e.g., HTTP Range parsing bugs). Offset arithmetic like off = start - prefix where start < prefix. Parsers that interpret a signed 'seek backward' count as an absolute offset without clamping.

Related errors


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