{"record":{"id":"bad9112c97263ba0","repo":"AlistGo/alist","slug":"failed-extracting-file-size","errorCode":null,"errorMessage":"failed extracting file size","messagePattern":"failed extracting file size","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/net/request.go","lineNumber":499,"sourceCode":"\tif len(contentRange) == 0 {\n\t\t// ContentRange is nil when the full file contents is provided, and\n\t\t// is not chunked. Use ContentLength instead.\n\t\tif resp.ContentLength > 0 {\n\t\t\ttotalBytes = resp.ContentLength\n\t\t}\n\t} else {\n\t\tparts := strings.Split(contentRange, \"/\")\n\n\t\ttotal := int64(-1)\n\n\t\t// Checking for whether a numbered total exists\n\t\t// If one does not exist, we will assume the total to be -1, undefined,\n\t\t// and sequentially download each chunk until hitting a 416 error\n\t\ttotalStr := parts[len(parts)-1]\n\t\tif totalStr != \"*\" {\n\t\t\ttotal, err = strconv.ParseInt(totalStr, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\terr = fmt.Errorf(\"failed extracting file size\")\n\t\t\t}\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"file size unknown\")\n\t\t}\n\n\t\ttotalBytes = total\n\t}\n\tif totalBytes != d.params.Size && err == nil {\n\t\terr = fmt.Errorf(\"expect file size=%d unmatch remote report size=%d, need refresh cache\", d.params.Size, totalBytes)\n\t}\n\tif err != nil {\n\t\t// _ = d.interrupt()\n\t\td.setErr(err)\n\t\td.cancel(err)\n\t}\n\treturn err\n\n}","sourceCodeStart":481,"sourceCodeEnd":517,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/internal/net/request.go#L481-L517","documentation":"In checkTotalBytes, when the Content-Range header's total part exists (not '*') but strconv.ParseInt fails, the original parse error is replaced with this opaque message. The total file size is needed to plan chunk ranges, so an unparseable total aborts the download (setErr + cancel).","triggerScenarios":"Server returns a Content-Range like 'bytes 0-99/abc' or 'bytes 0-99/12GB' where the segment after '/' is not a plain base-10 integer.","commonSituations":"Buggy or non-standard storage backends; a hand-written mock server; intermediate proxies rewriting Content-Range; exotic object stores with proprietary units.","solutions":["Capture the raw Content-Range header to see what the server actually sent.","Fix/replace the backend or proxy that emits a malformed Content-Range total.","If you control the server, emit 'bytes start-end/total' with a numeric total.","If the size is genuinely unknown, have the server send '*' so the downloader uses its sequential 416-based path instead."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Validate a Content-Range total before relying on it\nparts := strings.Split(contentRange, \"/\")\nif total := parts[len(parts)-1]; total != \"*\" {\n    if _, err := strconv.ParseInt(total, 10, 64); err != nil {\n        // do not plan chunks; handle unknown/invalid size explicitly\n    }\n}","typeGuard":"strings.Contains(err.Error(), \"failed extracting file size\")","tryCatchPattern":"if err := d.checkTotalBytes(resp); err != nil {\n    if strings.Contains(err.Error(), \"failed extracting file size\") {\n        // log raw header, fall back to sequential download or abort\n    }\n}","preventionTips":["When adding a storage driver, always emit numeric totals in Content-Range for ranged responses.","Add integration tests asserting the exact 'bytes start-end/total' format.","Watch for middleboxes/proxies that rewrite range headers."],"tags":["network","download","http-headers","content-range","go"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}