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

  1. Retry the move after confirming the source file is stable
  2. Check disk health and free space on the destination volume
  3. Verify the source file is not being written by another process during the move
  4. 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

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


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)