immich-app/immich · warning
Skipping move due to file size mismatch
Error message
Skipping move due to file size mismatch
What it means
When a direct rename across filesystems fails, moveFile falls back to copy-verify-delete. If the copied file's size does not match the expected size, the move is deliberately skipped: the new file is unlinked and the original is left in place, and only a warning is logged.
Solutions
- Retry the move after confirming the source file is stable
- Check disk health and free space on the destination volume
- Verify the source file is not being written by another process during the move
- Investigate the storage backend's copyFile implementation for silent truncation
Defensive patterns
Strategy: fallback
Validate before calling
const oldStat = await fs.promises.stat(oldPath);
const newStat = await fs.promises.stat(newPath);
if (newStat.size !== oldStat.size) { await fs.promises.unlink(newPath); return false; } Try / catch
const moved = await storageCore.moveFile(type, id, newPath);
if (!moved) {
logger.warn('move skipped; original file retained at ' + oldPath);
scheduleRetry(oldPath, newPath);
} Prevention
- Quiesce sync/upload jobs during bulk moves
- Monitor free space on destination volumes
- Alert on 'Skipping move due to file size mismatch' warnings — original stays in place
- Ensure source files are fully written before moving
When it happens
Trigger: moveFile (via moveAssetImage/moveAssetVideo/movePersonFile) falls back to copyFile because rename failed, and verifyNewPathContentsMatchesExpected returns false because newPath size differs from oldStat.size (or assetInfo.sizeInBytes).
Common situations: Copy interrupted or source file changed/truncated mid-copy; partially failed disk; source file modified between stat and copy; storage backend reports wrong sizes (some network mounts).
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Unable to complete move. File size mismatch
- Failed to create
- Failed to read: " ( )
- Unable to complete move. File checksum mismatch
- Asset dimensions are not available for editing
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/c8a84d67a6703838.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/cores/storage.core.ts:256
return;
}
if (move.oldPath !== newPath) {
try {
this.logger.debug(`Attempting to rename file: ${move.oldPath} => ${newPath}`);
await this.storageRepository.rename(move.oldPath, newPath);
} catch (error: any) {
if (error.code !== 'EXDEV') {
this.logger.warn(
`Unable to complete move. Error renaming file with code ${error.code} and message: ${error.message}`,
);
return;
}
this.logger.debug(`Unable to rename file. Falling back to copy, verify and delete`);
await this.storageRepository.copyFile(move.oldPath, newPath);
if (!(await this.verifyNewPathContentsMatchesExpected(move.oldPath, newPath, assetInfo))) {
this.logger.warn(`Skipping move due to file size mismatch`);
await this.storageRepository.unlink(newPath);
return;
}
const { atime, mtime } = await this.storageRepository.stat(move.oldPath);
await this.storageRepository.utimes(newPath, atime, mtime);
try {
await this.storageRepository.unlink(move.oldPath);
} catch (error: any) {
this.logger.warn(`Unable to delete old file, it will now no longer be tracked by Immich: ${error.message}`);
}
}
}
await this.savePath(pathType, entityId, newPath, ownerId);
await this.moveRepository.delete(move.id);
}View on GitHub (pinned to e55ac299a4)