immich-app/immich · warning
Unable to resolve realpath
Error message
Unable to resolve realpath
What it means
This warning is logged by the download service when resolving the symbolic/real path of a file to include in a downloadable archive fails. The storage repository's realpath call throws (e.g. the file vanished or the link is broken), and instead of failing the whole archive, the service logs and falls back to the un-resolved path. It is non-fatal by design.
Solutions
- Verify the file exists at originalPath/editedPath on the storage volume and the symlink target is intact
- Check that external library volumes are mounted and reachable by the server
- Re-run the download; if persistent, refresh the library so dead entries are purged
- If path rewriting matters, fix permissions on parent directories so realpath can traverse them
Example fix
// before
try { realpath = await this.storageRepository.realpath(realpath); } catch { this.logger.warn('Unable to resolve realpath', { originalPath }); }
// after
try { realpath = await this.storageRepository.realpath(realpath); } catch (err) { this.logger.warn('Unable to resolve realpath', { originalPath, error: err }); if (!(await this.storageRepository.exists(realpath))) { continue; } } Defensive patterns
Strategy: try-catch
Validate before calling
import { stat, realpath } from 'fs/promises';
async function pathResolvable(p: string): Promise<boolean> {
try { await realpath(p); return true; } catch { return false; }
} Try / catch
try {
realpath = await storageRepository.realpath(realpath);
} catch {
logger.warn('Unable to resolve realpath', { originalPath });
// decide: skip the file or proceed with un-resolved path
} Prevention
- Check file/symlink existence before enqueueing downloads
- Keep external volumes mounted and monitored
- Purge library entries whose files vanished
- Log the underlying error, not just the path
When it happens
Trigger: A user downloads an archive while one of the selected files was deleted/moved on disk between selection and zip creation, or the path is a broken symlink that realpath cannot resolve on the storage backend.
Common situations: Race between asset selection and download; external storage/volume remounted or offline; broken symlinks in the library; file removed by a concurrent library-deletion job.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- assetIds, albumId, or userId is required
- Attempted to clear cache, but rmtree is not safe on this…
- Failed to create
- Failed to read: " ( )
- Failed to read helmet file
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/19b531517aecd1cf.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/download.service.ts:117
continue;
}
const { originalPath, editedPath, originalFileName } = asset;
let filename = sanitize(originalFileName) || 'unnamed';
const count = paths[filename] || 0;
paths[filename] = count + 1;
if (count !== 0) {
const parsedFilename = parse(filename);
filename = `${parsedFilename.name}+${count}${parsedFilename.ext}`;
}
let realpath = dto.edited && editedPath ? editedPath : originalPath;
try {
realpath = await this.storageRepository.realpath(realpath);
} catch {
this.logger.warn('Unable to resolve realpath', { originalPath });
}
zip.addFile(realpath, filename);
}
void zip.finalize();
return {
stream: zip.stream,
disposition: dto.archiveName && `attachment; filename*=UTF-8''${encodeURIComponent(dto.archiveName)}.zip`,
};
}
}
View on GitHub (pinned to e55ac299a4)