invoke-ai/InvokeAI · error

Destination image already exists: {move.new_path}

Error message

Destination image already exists: {move.new_path}

What it means

preflight_moves raises FileExistsError when the destination image path already exists on disk, preventing an overwrite of user data by the move operation. The check runs only when the source exists, and before the move is recorded.

Source

Thrown at invokeai/app/services/image_moves/image_moves_default.py:435

                    str(move.old_path),
                    str(move.new_path),
                    str(move.old_thumbnail_path),
                    str(move.new_thumbnail_path),
                    message,
                ),
            )
            return job_id

    def preflight_moves(self, moves: Sequence[PlannedImageMove]) -> None:
        destinations: set[Path] = set()
        thumbnail_destinations: set[Path] = set()
        for move in moves:
            if not move.old_path.exists():
                if not move.is_intermediate:
                    raise FileNotFoundError(f"Source image does not exist: {move.old_path}")
                continue
            if move.new_path.exists():
                raise FileExistsError(f"Destination image already exists: {move.new_path}")
            if move.old_path == move.new_path:
                raise ValueError(f"Old and new paths are identical for {move.image_name}")
            if move.new_path in destinations:
                raise ValueError(f"Duplicate destination path: {move.new_path}")
            destinations.add(move.new_path)
            if move.new_thumbnail_path in thumbnail_destinations:
                raise ValueError(f"Duplicate destination thumbnail path: {move.new_thumbnail_path}")
            thumbnail_destinations.add(move.new_thumbnail_path)
            if self._has_active_job_for_image(move.image_name):
                raise ValueError(f"Image {move.image_name} already has an active image move job")
            self._assert_same_filesystem(move.old_path, move.new_path)
            if move.old_thumbnail_path.exists():
                if move.new_thumbnail_path.exists():
                    raise FileExistsError(f"Destination thumbnail already exists: {move.new_thumbnail_path}")
                self._assert_same_filesystem(move.old_thumbnail_path, move.new_thumbnail_path)

    def _record_missing_source_errors(self, moves: Sequence[PlannedImageMove]) -> tuple[list[PlannedImageMove], int]:
        remaining_moves: list[PlannedImageMove] = []

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Run startup_recovery/complete_partial_filesystem_moves to finish or reconcile the earlier job instead of re-planning
  2. Choose a different destination subfolder or rename to avoid the collision
  3. Remove or rename the pre-existing destination file if it is safe to discard
  4. Detect and skip already-moved images in the caller before planning

Example fix

// before
service.preflight_moves(moves)  # FileExistsError
// after
moves = [m for m in moves if not m.new_path.exists()]
if moves:
    service.preflight_moves(moves)
Defensive patterns

Strategy: validation

Validate before calling

conflicts = [m for m in moves if m.old_path.exists() and m.new_path.exists()]
if conflicts:
    raise FileExistsError(f"destinations exist: {[str(m.new_path) for m in conflicts]}")
service.preflight_moves(moves)

Type guard

def destination_free(move: PlannedImageMove) -> bool:
    return not move.new_path.exists()

Try / catch

try:
    service.preflight_moves(moves)
except FileExistsError as e:
    run_startup_recovery_or_choose_new_destination(e)

Prevention

When it happens

Trigger: Re-running a move after a previous run already copied/moved files to the destination; two images resolving to the same destination name via path collisions; destination folder seeded externally with same-named files.

Common situations: Retrying a partially-completed move without recovery; importing images into a folder that already contains same-named outputs; case-insensitive filesystems colliding names that differ only by case.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/15367db10c5eeb48. Report an issue: GitHub.