gofr-dev/gofr · error

%w: negative offset %d

Error message

%w: negative offset %d

What it means

ReadAt wraps ErrOutOfRange with the offending value when given a negative offset, because a byte position below zero can never be valid in S3 (object keys are byte-addressed from 0). The request is rejected locally before any network call is made, so it fails fast and cheaply.

Source

Thrown at pkg/gofr/datasource/file/s3/file.go:207

func (f *S3File) ReadAt(p []byte, offset int64) (n int, err error) {
	bucketName := getBucketName(f.name)
	fileName := f.relativeKey()

	var msg string

	st := statusErr

	defer f.sendOperationStats(&FileLog{
		Operation: "READAT",
		Location:  getLocation(bucketName),
		Status:    &st,
		Message:   &msg,
	}, time.Now())

	// A negative offset is never valid. Reject it before spending a request.
	if offset < 0 {
		msg = fmt.Sprintf("Negative offset %v", offset)
		return 0, fmt.Errorf("%w: negative offset %d", ErrOutOfRange, offset)
	}

	// An empty destination reads nothing; return without a request.
	if len(p) == 0 {
		st = statusSuccess
		return 0, nil
	}

	// A read that starts at or past EOF has nothing to return. Guard here so it
	// costs no request and, importantly, so io.ReaderAt callers see io.EOF rather
	// than an unsatisfiable Range (bytes=<size>-...) turning into an HTTP 416.
	// A read that merely straddles EOF (offset < size <= offset+len(p)) is valid:
	// S3 returns the available bytes and io.ReadFull below surfaces the short fill
	// as io.EOF along with the real count, honoring the io.ReaderAt contract.
	if offset >= f.size {
		st = statusSuccess
		return 0, io.EOF
	}

View on GitHub (pinned to 187eb24962)

Solutions

  1. Validate the offset before calling: if offset < 0 { return/adjust }.
  2. Fix offset computation so it cannot go negative (clamp to 0 or use unsigned/checked math).
  3. Use Seek/Read for relative positioning instead of negative ReadAt offsets.
  4. Handle errors.Is(err, s3.ErrOutOfRange) to distinguish caller bugs from I/O errors.

Example fix

// before
n, err := f.ReadAt(buf, -1)
// after
if offset < 0 { return fmt.Errorf("invalid offset %d", offset) }
n, err := f.ReadAt(buf, offset)
Defensive patterns

Strategy: validation

Validate before calling

func safeReadAt(f *s3datasource.S3File, p []byte, off int64) (int, error) {
    if off < 0 {
        return 0, fmt.Errorf("offset must be >= 0, got %d", off)
    }
    return f.ReadAt(p, off)
}

Type guard

func validOffset(off int64) bool { return off >= 0 }

Prevention

When it happens

Trigger: Calling (*S3File).ReadAt(p []byte, offset) with offset < 0 — e.g. a computed offset that underflowed, or passing -1 as a 'don't care' sentinel as some APIs allow.

Common situations: Integer arithmetic bugs producing negative positions (size subtraction going negative); porting code from APIs where -1 means 'read from current position'; unvalidated user-supplied offsets.

Related errors


AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01). Data as JSON: /api/errors/ac1369e6291c271b. Report an issue: GitHub.