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
- Validate off >= 0 before calling ReadAt; if a relative seek is intended, compute the absolute offset and clamp at 0.
- If off is derived from user input, sanitize it (max(0, off)) and surface a clear error to the caller.
- Switch to Reader.Seek + Read if you need relative positioning semantics instead of absolute ReadAt.
- 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
- Always validate off >= 0 before ReadAt.
- For relative seeks, compute the absolute offset and clamp at 0.
- Sanitize offsets originating from user input (Range headers, cursors).
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
- bytes.Reader.UnreadByte: at beginning of slice
- bytes.Reader.UnreadRune: at beginning of slice
- bytes.Reader.UnreadRune: previous operation was not ReadRune
- bytes.Reader.Seek: invalid whence
- bytes.Reader.Seek: negative position
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/79232ba53d10b15a.
Report an issue: GitHub.