{"record":{"id":"9ea67d2aa7939c49","repo":"AlistGo/alist","slug":"invalid-range-failed-to-overlap","errorCode":null,"errorMessage":"invalid range: failed to overlap","messagePattern":"invalid range: failed to overlap","errorType":"http","errorClass":"ErrNoOverlap","httpStatus":416,"severity":"warning","filePath":"pkg/http_range/range.go","lineNumber":27,"sourceCode":"\t\"strconv\"\n\t\"strings\"\n)\n\n// Range specifies the byte range to be sent to the client.\ntype Range struct {\n\tStart  int64\n\tLength int64 // limit of bytes to read, -1 for unlimited\n}\n\n// ContentRange returns Content-Range header value.\nfunc (r Range) ContentRange(size int64) string {\n\treturn fmt.Sprintf(\"bytes %d-%d/%d\", r.Start, r.Start+r.Length-1, size)\n}\n\nvar (\n\t// ErrNoOverlap is returned by ParseRange if first-byte-pos of\n\t// all the byte-range-spec values is greater than the content size.\n\tErrNoOverlap = errors.New(\"invalid range: failed to overlap\")\n\n\t// ErrInvalid is returned by ParseRange on invalid input.\n\tErrInvalid = errors.New(\"invalid range\")\n)\n\n// ParseRange parses a Range header string as per RFC 7233.\n// ErrNoOverlap is returned if none of the ranges overlap.\n// ErrInvalid is returned if s is invalid range.\nfunc ParseRange(s string, size int64) ([]Range, error) { // nolint:gocognit\n\tif s == \"\" {\n\t\treturn nil, nil // header not present\n\t}\n\tconst b = \"bytes=\"\n\tif !strings.HasPrefix(s, b) {\n\t\treturn nil, ErrInvalid\n\t}\n\tvar ranges []Range\n\tnoOverlap := false","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/pkg/http_range/range.go#L9-L45","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nranges, err := http_range.ParseRange(r.Header.Get(\"Range\"), staleSize)\n\n// after\nranges, err := http_range.ParseRange(r.Header.Get(\"Range\"), currentSize)\nif errors.Is(err, http_range.ErrNoOverlap) {\n    w.Header().Set(\"Content-Range\", fmt.Sprintf(\"bytes */%d\", currentSize))\n    http.Error(w, \"Requested Range Not Satisfiable\", http.StatusRequestedRangeNotSatisfiable)\n    return\n}","handlingStrategy":"try-catch","validationCode":"if start := requestedStart(); start >= 0 && start >= currentSize {\n\t// client already has everything; answer 416 or full body per RFC 7233\n}","typeGuard":null,"tryCatchPattern":"ranges, err := http_range.ParseRange(hdr, size)\nif errors.Is(err, http_range.ErrNoOverlap) {\n\tw.Header().Set(\"Content-Range\", fmt.Sprintf(\"bytes */%d\", size))\n\thttp.Error(w, \"range not satisfiable\", http.StatusRequestedRangeNotSatisfiable)\n\treturn\n}","preventionTips":["Always pass the freshly fetched content length to ParseRange","Handle 416 in download clients by restarting the download from byte 0"],"tags":["http","range","rfc7233","download"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}