{"record":{"id":"86b0d6fa5fa1ad56","repo":"AlistGo/alist","slug":"doesnot-support-length-bigger-than-int32-max","errorCode":null,"errorMessage":"doesnot support length bigger than int32 max ","messagePattern":"doesnot support length bigger than int32 max ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/net/util.go","lineNumber":338,"sourceCode":"\t\tbuf = buf[0:l.remaining]\n\t}\n\n\tn, err := l.rc.Read(buf)\n\tl.remaining -= n\n\n\treturn n, err\n}\n\nfunc (l *LimitedReadCloser) Close() error {\n\treturn l.rc.Close()\n}\n\n// GetRangedHttpReader some http server doesn't support \"Range\" header,\n// so this function read readCloser with whole data, skip offset, then return ReaderCloser.\nfunc GetRangedHttpReader(readCloser io.ReadCloser, offset, length int64) (io.ReadCloser, error) {\n\tvar length_int int\n\tif length > math.MaxInt {\n\t\treturn nil, fmt.Errorf(\"doesnot support length bigger than int32 max \")\n\t}\n\tlength_int = int(length)\n\n\tif offset > 100*1024*1024 {\n\t\tlog.Warnf(\"offset is more than 100MB, if loading data from internet, high-latency and wasting of bandwidth is expected\")\n\t}\n\n\tif _, err := utils.CopyWithBuffer(io.Discard, io.LimitReader(readCloser, offset)); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// return an io.ReadCloser that is limited to `length` bytes.\n\treturn &LimitedReadCloser{readCloser, length_int}, nil\n}\n","sourceCodeStart":320,"sourceCodeEnd":353,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/internal/net/util.go#L320-L353","documentation":"GetRangedHttpReader rejects length values that cannot be represented as an int on the target platform (checked against math.MaxInt; message says int32 max though it means platform int). Because the fallback path reads the WHOLE body and discards offset bytes, a huge length would imply buffering an enormous slice, so it refuses up front.","triggerScenarios":"Calling GetRangedHttpReader with a length exceeding math.MaxInt (e.g. int64 value from a Content-Length or range calc passed on a 32-bit build), typically for a very large or unknown size encoded as a big int64.","commonSituations":"32-bit builds (linux/386, windows/386, arm) downloading multi-GB files through servers without Range support; callers computing length as file size or remaining bytes; size passed as -1 sentinel interpreted as huge.","solutions":["Clamp or validate length before calling: ensure 0 <= length <= math.MaxInt.","On 32-bit platforms, split the transfer into multiple smaller reads.","Prefer a server/path that supports Range headers so the discard-based fallback is not used.","Fix the caller passing an unvalidated int64 (e.g. contentLength) straight through."],"exampleFix":"// before\nreader, err := GetRangedHttpReader(res.Body, offset, contentLength) // contentLength int64\n\n// after\nlength := contentLength\nif length > int64(math.MaxInt) {\n    length = int64(math.MaxInt)\n}\nreader, err := GetRangedHttpReader(res.Body, offset, length)","handlingStrategy":"validation","validationCode":"const maxLen = int64(math.MaxInt)\nif length < 0 || length > maxLen {\n    length = maxLen // or split the transfer into segments\n}","typeGuard":"strings.Contains(err.Error(), \"doesnot support length\")","tryCatchPattern":"rc, err := GetRangedHttpReader(body, offset, length)\nif err != nil {\n    if strings.Contains(err.Error(), \"doesnot support length\") {\n        // split into <= MaxInt segments and loop\n    }\n}","preventionTips":["Validate int64 lengths against math.MaxInt before calling on 32-bit targets.","Prefer Range-capable servers so the whole-body-discard fallback is never used.","Avoid passing sentinel values like -1 as length; normalize them first."],"tags":["network","download","platform-limits","http-range","go"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}