gofr-dev/gofr · error
s3 backend did not honor the requested byte range
Error message
s3 backend did not honor the requested byte range
What it means
ErrRangeNotHonored is returned by Read/ReadAt when a byte-range GetObject request was sent (offset > 0) but the backend replied with the whole object and no Content-Range header. Accepting such a response would fill the caller's buffer starting at byte 0, silently serving wrong bytes, so the library refuses the read. It almost always indicates an S3-compatible backend that ignores Range headers.
Source
Thrown at pkg/gofr/datasource/file/s3/file.go:45
logger Logger
metrics Metrics
size int64
contentType string
body io.ReadCloser
lastModified time.Time
}
func (*S3File) Sys() any {
return nil
}
var (
ErrNilResponse = errors.New("response retrieved is nil ")
// ErrRangeNotHonored is returned when a byte-range read was requested but the
// backend answered with the whole object (no Content-Range header). Filling the
// caller's buffer from byte 0 in that case would silently serve the wrong bytes,
// so the read is refused instead.
ErrRangeNotHonored = errors.New("s3 backend did not honor the requested byte range")
)
// Close closes the response body returned in Open/Create methods if the response body is not nil.
func (f *S3File) Close() error {
bucketName := getBucketName(f.name)
defer f.sendOperationStats(&FileLog{
Operation: "CLOSE",
Location: getLocation(bucketName)}, time.Now())
if f.body != nil {
return f.body.Close()
}
return nil
}
// closeBody closes a previously opened response body (if any) before it isView on GitHub (pinned to 187eb24962)
Solutions
- Verify the backend honors Range requests: aws s3api get-object --range bytes=10- ... and check the Content-Range response header.
- Replace or reconfigure the non-conformant S3-compatible storage/proxy (MinIO/Ceph/nginx caching layer) so Range is honored.
- In tests, make the fake GetObject implementation return ContentRange (e.g. aws.String("bytes 10-99/100")) whenever a Range input is present.
- As a workaround, Seek back to 0 and read the whole object sequentially, since offset 0 sends no Range header.
Example fix
// test mock that triggers the error
res := &s3.GetObjectOutput{Body: body} // no ContentRange
// after
res := &s3.GetObjectOutput{Body: body, ContentRange: aws.String(fmt.Sprintf("bytes %d-%d/%d", off, total-1, total))} Defensive patterns
Strategy: fallback
Validate before calling
// probe backend range support once at startup:
out, err := client.GetObject(ctx, &s3.GetObjectInput{Bucket: b, Key: k, Range: aws.String("bytes=0-0")})
rangeOK := err == nil && out.ContentRange != nil Try / catch
n, err := f.Read(buf)
if errors.Is(err, s3datasource.ErrRangeNotHonored) {
// fallback: seek to 0 and stream the whole object sequentially
f.Seek(0, io.SeekStart)
return f.Read(buf)
} Prevention
- Verify Range/Content-Range support of your S3-compatible store before enabling offset reads.
- Disable middle-box caching that strips Range handling.
- Make test doubles return ContentRange when given a Range input.
- Prefer full sequential reads on backends known to ignore Range.
When it happens
Trigger: 1) (*S3File).Read with f.offset > 0 while res.ContentRange == nil; 2) (*S3File).ReadAt (which always sends a Range header) against a backend that ignores it. Both wrap nothing — the sentinel is returned directly.
Common situations: Using MinIO, Ceph, mock S3 servers, or caching proxies that ignore the Range header; serving reads after Seek pushed the offset past 0; test double S3 clients that return a full body without ContentRange.
Related errors
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/b964aff4ca16fb8e.
Report an issue: GitHub.