AlistGo/alist · warning · ErrNoOverlap
invalid range: failed to overlap
Error message
invalid range: failed to overlap
What it means
ErrNoOverlap from pkg/http_range.ParseRange: every byte-range-spec in a Range header starts beyond the content size, so none of the requested ranges intersect the resource. Returned when parsing a header like `bytes=5000-` against a 100-byte file.
Source
Thrown at pkg/http_range/range.go:27
"strconv"
"strings"
)
// Range specifies the byte range to be sent to the client.
type Range struct {
Start int64
Length int64 // limit of bytes to read, -1 for unlimited
}
// ContentRange returns Content-Range header value.
func (r Range) ContentRange(size int64) string {
return fmt.Sprintf("bytes %d-%d/%d", r.Start, r.Start+r.Length-1, size)
}
var (
// ErrNoOverlap is returned by ParseRange if first-byte-pos of
// all the byte-range-spec values is greater than the content size.
ErrNoOverlap = errors.New("invalid range: failed to overlap")
// ErrInvalid is returned by ParseRange on invalid input.
ErrInvalid = errors.New("invalid range")
)
// ParseRange parses a Range header string as per RFC 7233.
// ErrNoOverlap is returned if none of the ranges overlap.
// ErrInvalid is returned if s is invalid range.
func ParseRange(s string, size int64) ([]Range, error) { // nolint:gocognit
if s == "" {
return nil, nil // header not present
}
const b = "bytes="
if !strings.HasPrefix(s, b) {
return nil, ErrInvalid
}
var ranges []Range
noOverlap := falseView on GitHub (pinned to 843d9dc814)
Solutions
- Verify the size argument passed to ParseRange is the real current content length (re-stat the remote resource)
- If the client's range is legitimately past EOF (e.g. resume of a completed download), treat 416 semantics: satisfy the request with the full resource or return 416 with a Content-Range of the actual size per RFC 7233
- Clamp/validate requested offsets against size before calling ParseRange
Example fix
// before
ranges, err := http_range.ParseRange(r.Header.Get("Range"), staleSize)
// after
ranges, err := http_range.ParseRange(r.Header.Get("Range"), currentSize)
if errors.Is(err, http_range.ErrNoOverlap) {
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", currentSize))
http.Error(w, "Requested Range Not Satisfiable", http.StatusRequestedRangeNotSatisfiable)
return
} Defensive patterns
Strategy: try-catch
Validate before calling
if start := requestedStart(); start >= 0 && start >= currentSize {
// client already has everything; answer 416 or full body per RFC 7233
} Try / catch
ranges, err := http_range.ParseRange(hdr, size)
if errors.Is(err, http_range.ErrNoOverlap) {
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", size))
http.Error(w, "range not satisfiable", http.StatusRequestedRangeNotSatisfiable)
return
} Prevention
- Always pass the freshly fetched content length to ParseRange
- Handle 416 in download clients by restarting the download from byte 0
When it happens
Trigger: Calling http_range.ParseRange("bytes=5000-6000", 100) where start offset >= size for all specs; typically a client resuming a partial download against a truncated or replaced file.
Common situations: A downloader cached a file length from a previous version and the server file shrank, or the code passes the wrong size (0 or stale) to ParseRange.
Related errors
- invalid range
- missing cookie or qrcode account
- stopped after 10 redirects
- not found 302 redirect
- unexpected status code: %d
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/9ea67d2aa7939c49.
Report an issue: GitHub.