{"record":{"id":"e227f6da230e0a5a","repo":"AlistGo/alist","slug":"expect-file-size-d-unmatch-remote-report-size-d","errorCode":null,"errorMessage":"expect file size=%d unmatch remote report size=%d, need refresh cache","messagePattern":"expect file size=(.+?) unmatch remote report size=(.+?), need refresh cache","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/net/request.go","lineNumber":508,"sourceCode":"\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}\n\nfunc (d *downloader) incrWritten(n int64) {\n\td.m.Lock()\n\tdefer d.m.Unlock()\n\n\td.written += n\n}\n\n// getErr is a thread-safe getter for the error object","sourceCodeStart":490,"sourceCodeEnd":526,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/internal/net/request.go#L490-L526","documentation":"checkTotalBytes compares the server-reported total (from Content-Range) against the locally cached/expected size in d.params.Size; a mismatch means the remote file changed since metadata was cached. The downloader cancels itself (setErr + cancel) because all chunk ranges were planned from the stale size — the message even says 'need refresh cache'.","triggerScenarios":"File replaced/updated upstream (different size) between when alist cached its metadata and the ranged download; cached size from an old listing; copy/overwrite happening concurrently on the remote.","commonSituations":"Remote drive re-uploaded or versioned the file; user downloads right after an upstream edit; long-lived caches in database listing records.","solutions":["Refresh the directory listing / cached metadata for that file, then retry the download.","Implement the suggested cache invalidation: evict the file's cached size on this error and re-fetch metadata.","Retry the download after refresh — chunk planning will use the new size.","If it recurs constantly, check whether two processes keep overwriting the remote file."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"strings.Contains(err.Error(), \"need refresh cache\")","tryCatchPattern":"err := download()\nif err != nil && strings.Contains(err.Error(), \"need refresh cache\") {\n    op.InvalidateCache(path)      // evict stale size\n    _, _ = op.RefreshDirMetadata(ctx, path)\n    err = retryDownload()         // replan chunks with fresh size\n}","preventionTips":["Invalidate cached file metadata for files that failed with size mismatch before retrying.","Set sensible TTLs on listing caches for frequently-updated remote folders.","Refresh metadata right before large downloads of volatile files."],"tags":["network","download","cache","stale-metadata","go"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}