{"record":{"id":"cf4c708fa1bb05f1","repo":"valyala/fasthttp","slug":"byte-range-q-is-invalid-for-empty-content","errorCode":null,"errorMessage":"byte range %q is invalid for empty content","messagePattern":"byte range %q is invalid for empty content","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"fs.go","lineNumber":1504,"sourceCode":"\n\tb = b[len(strBytes):]\n\tif len(b) == 0 || b[0] != '=' {\n\t\treturn 0, 0, fmt.Errorf(\"missing byte range in %q\", byteRange)\n\t}\n\tb = b[1:]\n\n\tn := bytes.IndexByte(b, '-')\n\tif n < 0 {\n\t\treturn 0, 0, fmt.Errorf(\"missing the end position of byte range in %q\", byteRange)\n\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 {","sourceCodeStart":1486,"sourceCodeEnd":1522,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/fs.go#L1486-L1522","documentation":"The suffix form 'bytes=-N' means 'last N bytes'. This is meaningless when the resource is empty (Content-Length <= 0), so ParseByteRange rejects it instead of returning a bogus range.","triggerScenarios":"Requesting Range: bytes=-100 (or any '-N') against a zero-length file or a handler whose contentLength is 0 or negative; direct ParseByteRange(bytes=-N, 0) calls.","commonSituations":"Download resumers hitting a file truncated to 0 bytes (upload in progress, emptied log); serving empty placeholder files; caching layers that lost the real content length.","solutions":["Ensure the file actually has content before range-serving it — check size on the client with a HEAD request first","Handle the error server-side by falling back to serving the full (empty) body with 200","If the file was truncated by a rotation/refresh, retry after the writer finishes","For direct calls, guard: only pass contentLength > 0 when using suffix ranges"],"exampleFix":"// caller guard\nif contentLength > 0 {\n    start, end, err = fs.ParseByteRange(rangeHdr, contentLength)\n} else {\n    start, end, err = 0, -1, nil // serve empty body\n}","handlingStrategy":"validation","validationCode":"if contentLength <= 0 && isSuffixRange(hdr) {\n    // skip range negotiation; serve empty body with 200\n}","typeGuard":"func suffixRangeValid(hdr []byte, contentLength int) bool {\n    if !bytes.HasPrefix(hdr, []byte(\"bytes=-\")) { return true }\n    return contentLength > 0\n}","tryCatchPattern":"start, end, err := fs.ParseByteRange(hdr, cl)\nif err != nil && strings.Contains(err.Error(), \"invalid for empty content\") {\n    start, end = 0, -1 // serve empty body\n}","preventionTips":["Check file size (HEAD) before issuing suffix ranges","Avoid serving zero-byte files through range-aware endpoints","Re-upload/verify files truncated to 0 bytes before publishing","On this error, retry after confirming contentLength > 0"],"tags":["http","range-header","empty-content","fasthttp"],"backgroundTag":"range-invalid-empty-content","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}