{"record":{"id":"0b79ccefeba073df","repo":"valyala/fasthttp","slug":"the-start-position-of-byte-range-cannot-exceed-d","errorCode":null,"errorMessage":"the start position of byte range cannot exceed %d. byte range %q","messagePattern":"the start position of byte range cannot exceed (.+?)\\. byte range %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"fs.go","lineNumber":1514,"sourceCode":"\t}\n\n\tif n == 0 {\n\t\tv, err := ParseUint(b[n+1:])\n\t\tif err != nil {\n\t\t\treturn 0, 0, err\n\t\t}\n\t\tif contentLength <= 0 {\n\t\t\treturn 0, 0, fmt.Errorf(\"byte range %q is invalid for empty content\", byteRange)\n\t\t}\n\t\tstartPos := max(contentLength-v, 0)\n\t\treturn startPos, contentLength - 1, nil\n\t}\n\n\tif startPos, err = ParseUint(b[:n]); err != nil {\n\t\treturn 0, 0, err\n\t}\n\tif startPos >= contentLength {\n\t\treturn 0, 0, fmt.Errorf(\"the start position of byte range cannot exceed %d. byte range %q\", contentLength-1, byteRange)\n\t}\n\n\tb = b[n+1:]\n\tif len(b) == 0 {\n\t\treturn startPos, contentLength - 1, nil\n\t}\n\n\tif endPos, err = ParseUint(b); err != nil {\n\t\treturn 0, 0, err\n\t}\n\tif endPos >= contentLength {\n\t\tendPos = contentLength - 1\n\t}\n\tif endPos < startPos {\n\t\treturn 0, 0, fmt.Errorf(\"the start position of byte range cannot exceed the end position. byte range %q\", byteRange)\n\t}\n\treturn startPos, endPos, nil\n}","sourceCodeStart":1496,"sourceCodeEnd":1532,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/fs.go#L1496-L1532","documentation":"For 'bytes=start-end' the start offset must be within the content (startPos < contentLength). If the requested start is beyond the last byte, the server cannot satisfy the range and returns this error quoting the max valid start (contentLength-1).","triggerScenarios":"A resume/download client sends Range: bytes=5000-6000 for a 4000-byte file; a stale resume offset after the file shrank or was replaced; direct ParseByteRange with startPos >= contentLength.","commonSituations":"HTTP resume logic that kept an old offset after the remote file changed size; off-by-one in client code using size instead of size-1; serving a different (smaller) file version than the one the client previously fetched.","solutions":["Clamp the client offset: use min(offset, contentLength-1) and re-fetch size via HEAD before resuming","Use If-Range / ETag validation so stale offsets trigger a full re-download instead of an invalid range","Treat a 416 (mapped from this error) as 'file changed': reset the offset and restart the download","For direct calls, check startPos < contentLength yourself and skip range negotiation when it fails"],"exampleFix":"// before\nclient sends: Range: bytes=5000-\n// after — clamp using current size\nsize := head(url).ContentLength\nstart := min(resumeOffset, size-1)\nreq.Header.Set(\"Range\", fmt.Sprintf(\"bytes=%d-\", start))","handlingStrategy":"validation","validationCode":"if start := resumeOffset; start >= fileSize {\n    start = fileSize - 1 // or restart download\n}","typeGuard":"func rangeStartValid(start, contentLength int) bool {\n    return start >= 0 && start < contentLength\n}","tryCatchPattern":"start, end, err := fs.ParseByteRange(hdr, cl)\nvar rangeErr *fs.ErrRange // or string check\nif err != nil && strings.Contains(err.Error(), \"cannot exceed\") {\n    return 416 // client must reset its offset\n}","preventionTips":["Re-fetch Content-Length via HEAD before every resume","Use ETag/If-Range so stale offsets trigger a full re-download","Clamp offsets with min(offset, size-1) client-side","Never assume a previously fetched file size is still current"],"tags":["http","range-header","resume-download","fasthttp"],"backgroundTag":"range-start-out-of-bounds","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}