{"record":{"id":"80aca22a17288c41","repo":"immich-app/immich","slug":"stats-not-found-for-filepath","errorCode":null,"errorMessage":"Stats not found for ${filepath}","messagePattern":"Stats not found for (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/asset.ts","lineNumber":266,"sourceCode":"      // Update progress based on total size of processed files\n      let processedSize = 0;\n      for (const asset of assets) {\n        const stats = statsMap.get(asset.id);\n        processedSize += stats?.size || 0;\n      }\n      checkProgressBar?.increment(processedSize);\n    },\n    { concurrency, retry: 3 },\n  );\n\n  const results: { id: string; checksum: string }[] = [];\n  let checkBulkUploadRequests: AssetBulkUploadCheckItem[] = [];\n\n  const queue = new Queue<string, AssetBulkUploadCheckItem[]>(\n    async (filepath: string): Promise<AssetBulkUploadCheckItem[]> => {\n      const stats = statsMap.get(filepath);\n      if (!stats) {\n        throw new Error(`Stats not found for ${filepath}`);\n      }\n      const dto = { id: filepath, checksum: await sha1(filepath) };\n\n      results.push(dto);\n      checkBulkUploadRequests.push(dto);\n      if (checkBulkUploadRequests.length === 5000) {\n        const batch = checkBulkUploadRequests;\n        checkBulkUploadRequests = [];\n        void checkBulkUploadQueue.push(batch);\n      }\n\n      hashProgressBar?.increment(stats.size);\n      return results;\n    },\n    { concurrency, retry: 3 },\n  );\n\n  for (const item of files) {","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/packages/cli/src/commands/asset.ts#L248-L284","documentation":"In Immich's CLI duplicate-check step (checkForDuplicates), each queued file path must have a corresponding entry in the in-memory statsMap built from an earlier directory walk. If statsMap.get(filepath) returns undefined, the internal invariant that the queue is only fed paths that were stat-ed has been violated, so a plain Error is thrown with the offending path. It signals an internal bookkeeping bug, not a problem with the file itself.","triggerScenarios":"A filepath is pushed into the checkForDuplicates queue (from crawl results) that was never inserted into statsMap; typically because the file was deleted or modified between crawling and stat-ing, or the crawl and stat phases used different path normalization (case, trailing separators, relative vs absolute paths).","commonSituations":"Files disappearing mid-run (network mounts, sync tools like Dropbox/Google Drive removing files during upload), symlink or case-insensitive-filesystem paths that resolve differently between the crawl and the stat lookup, or running an older CLI against a newer crawl output.","solutions":["Re-run the upload; transient deletion during the crawl is the most common cause.","Verify all paths come from the same crawl run and the file still exists before uploading (test -f <path>).","Check for path-normalization mismatches (relative vs absolute, symlinked folders, case differences) in your --paths/-i inputs.","If reproducible on stable local files, report it as an Immich CLI bug with the logged filepath."],"exampleFix":"// before: rely on internal map\nconst stats = statsMap.get(filepath);\nif (!stats) throw new Error(`Stats not found for ${filepath}`);\n// after: guard in the caller before queueing\nfor (const filepath of files) {\n  const stats = await fs.promises.stat(filepath);\n  statsMap.set(filepath, stats); // re-sync before pushing\n  queue.push(filepath);\n}","handlingStrategy":"try-catch","validationCode":"import { statSync } from 'node:fs';\nconst files = crawlOutput.filter((f) => statSync(f) && statsMap.has(f));","typeGuard":"const hasStats = (f: string): f is string & { stats: fs.Stats } => statsMap.has(f);","tryCatchPattern":"try {\n  await queue.push(filepath);\n} catch (err) {\n  if (String(err).includes('Stats not found')) {\n    console.warn(`skipping ${filepath}: file vanished between crawl and upload`);\n    return null;\n  }\n  throw err;\n}","preventionTips":["Re-stat files immediately before queueing instead of trusting a long-lived statsMap","Use absolute, normalized paths consistently in crawl and upload phases","Avoid deleting/moving files while an upload session is running"],"tags":["internal-state","filesystem","cli","race-condition"],"backgroundTag":"record-not-found","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}