immich-app/immich · error · Error
Stats not found for
Error message
Stats not found for ${filepath} What it means
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.
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.
Example fix
// before: rely on internal map
const stats = statsMap.get(filepath);
if (!stats) throw new Error(`Stats not found for ${filepath}`);
// after: guard in the caller before queueing
for (const filepath of files) {
const stats = await fs.promises.stat(filepath);
statsMap.set(filepath, stats); // re-sync before pushing
queue.push(filepath);
} Defensive patterns
Strategy: try-catch
Validate before calling
import { statSync } from 'node:fs';
const files = crawlOutput.filter((f) => statSync(f) && statsMap.has(f)); Type guard
const hasStats = (f: string): f is string & { stats: fs.Stats } => statsMap.has(f); Try / catch
try {
await queue.push(filepath);
} catch (err) {
if (String(err).includes('Stats not found')) {
console.warn(`skipping ${filepath}: file vanished between crawl and upload`);
return null;
}
throw err;
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Admin account does not exist
- Attempted to clear cache, but rmtree is not safe on this…
- await response.text()
- Could not find asset
- Failed to create
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/80aca22a17288c41.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/commands/asset.ts:266
// Update progress based on total size of processed files
let processedSize = 0;
for (const asset of assets) {
const stats = statsMap.get(asset.id);
processedSize += stats?.size || 0;
}
checkProgressBar?.increment(processedSize);
},
{ concurrency, retry: 3 },
);
const results: { id: string; checksum: string }[] = [];
let checkBulkUploadRequests: AssetBulkUploadCheckItem[] = [];
const queue = new Queue<string, AssetBulkUploadCheckItem[]>(
async (filepath: string): Promise<AssetBulkUploadCheckItem[]> => {
const stats = statsMap.get(filepath);
if (!stats) {
throw new Error(`Stats not found for ${filepath}`);
}
const dto = { id: filepath, checksum: await sha1(filepath) };
results.push(dto);
checkBulkUploadRequests.push(dto);
if (checkBulkUploadRequests.length === 5000) {
const batch = checkBulkUploadRequests;
checkBulkUploadRequests = [];
void checkBulkUploadQueue.push(batch);
}
hashProgressBar?.increment(stats.size);
return results;
},
{ concurrency, retry: 3 },
);
for (const item of files) {View on GitHub (pinned to e55ac299a4)