AlistGo/alist · error
range start out of bound
Error message
range start out of bound
What it means
Range-validation error inside Chunker.openChunkReader, which assembles a reader over chunk parts to serve an HTTP Range request on a chunked file. The requested start offset is rejected when it is negative or greater than the file's total size (as recorded in chunk metadata). This is a precondition failure before any chunk is opened — the requested window simply cannot exist within the logical file.
Source
Thrown at drivers/chunker/util.go:832
func (d *Chunker) buildKeepSet(locations ...objectLocation) map[string]struct{} {
keep := make(map[string]struct{}, len(locations))
for _, location := range locations {
if location.LogicalPath == "" {
continue
}
keep[d.keepKey(location)] = struct{}{}
}
return keep
}
func (d *Chunker) chunkPartBaseName(filePath string, chunkNo int, xactID string) string {
return path.Base(d.makeChunkName(filePath, chunkNo, xactID))
}
func (d *Chunker) openChunkReader(ctx context.Context, parts []linkedPart, totalSize int64, req http_range.Range) (io.ReadCloser, error) {
if req.Start < 0 || req.Start > totalSize {
return nil, fmt.Errorf("range start out of bound")
}
if req.Length < 0 || req.Start+req.Length > totalSize {
req.Length = totalSize - req.Start
}
if req.Length == 0 {
return io.NopCloser(strings.NewReader("")), nil
}
var (
readers []io.Reader
closers = utils.EmptyClosers()
offset int64
remaining = req.Length
)
for _, part := range parts {
partStart := offset
partEnd := offset + part.part.Size
offset = partEndView on GitHub (pinned to 843d9dc814)
Solutions
- Clamp the requested start to the file's actual size and serve an empty body or 416 when the range is unsatisfiable, instead of propagating the raw error
- Verify the chunked object's metadata totalSize matches the sum of chunk part sizes; re-upload or repair metadata if they diverge
- Fix callers that construct http_range.Range without validating Start against the object size
Example fix
// before
reader, err := d.openChunkReader(ctx, parts, total, req)
// after
if req.Start < 0 || req.Start > total {
req.Start = total
req.Length = 0
}
reader, err := d.openChunkReader(ctx, parts, total, req) Defensive patterns
Strategy: validation
Validate before calling
// sanitize the range before opening a chunked read
func sanitizeRange(req http_range.Range, total int64) (http_range.Range, error) {
if req.Start < 0 {
req.Start = 0
}
if req.Start > total {
return req, fmt.Errorf("unsatisfiable range: start %d > size %d", req.Start, total)
}
if req.Length < 0 || req.Start+req.Length > total {
req.Length = total - req.Start
}
return req, nil
} Type guard
func rangeSatisfiable(req http_range.Range, totalSize int64) bool {
return req.Start >= 0 && req.Start <= totalSize
} Try / catch
reader, err := d.openChunkReader(ctx, parts, total, req)
if err != nil {
if strings.Contains(err.Error(), "range start out of bound") {
// serve 416 or empty body instead of a 500
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", total))
w.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
return
}
return err
} Prevention
- Always clamp Range values against the object's real size before use
- Treat out-of-bound ranges as 416 responses, not internal errors
- Keep chunk metadata totalSize in sync with actual part sizes; repair after interrupted uploads
When it happens
Trigger: Serving a range request (video seeking, partial download, web seed client) where req.Start > totalSize or req.Start < 0: client asks for bytes beyond EOF; stale chunk metadata claims a smaller totalSize than the real file (or the file shrank); corrupted/truncated metadata after an interrupted chunked upload; unit tests passing an unsanitized Range struct.
Common situations: Media players requesting a seek position past the end of a chunked video; chunk metadata out of sync after manual edits to the remote store; a partial chunk upload leaving totalSize=0 while clients still issue range reads.
Related errors
- unsupported meta_format: %s
- unsupported hash_type: %s
- hash_type %q requires meta_format=simplejson
- remote_path is required
- chunk_size must be positive
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/a159d19bfc7d3d9c.
Report an issue: GitHub.