invoke-ai/InvokeAI · error

Both old and new image files exist for {item.image_name}

Error message

Both old and new image files exist for {item.image_name}

What it means

Raised by _complete_partial_filesystem_move when, before committing a batch image move, both the old and new image file paths exist on disk. This is an ambiguous state — the move may have been partially executed plus a duplicate copy left behind — so the code refuses to guess which file is authoritative and aborts that item with a RuntimeError instead of silently overwriting data.

Source

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

                if not self._is_unrecoverable_error(e):
                    raise
                self._reconcile_destination_subfolder(item)
                self.mark_item_unrecoverable(job_id, item.image_name, f"{item.image_name}: {e}")
                self._logger.error("Image move skipped unrecoverable item %s: %s", item.image_name, e)

    def _complete_partial_filesystem_move(self, job_id: int, item: PlannedImageMove) -> None:
        old_path = self.image_files.get_path(item.image_name, image_subfolder=item.old_subfolder)
        new_path = self.image_files.get_path(item.image_name, image_subfolder=item.new_subfolder)
        old_thumbnail_path = self.image_files.get_path(
            item.image_name, thumbnail=True, image_subfolder=item.old_subfolder
        )
        new_thumbnail_path = self.image_files.get_path(
            item.image_name, thumbnail=True, image_subfolder=item.new_subfolder
        )
        old_exists = old_path.exists()
        new_exists = new_path.exists()
        if old_exists and new_exists:
            raise RuntimeError(f"Both old and new image files exist for {item.image_name}")
        if not old_exists and not new_exists:
            if item.is_intermediate:
                self._mark_missing_intermediate_moved(
                    job_id=job_id,
                    image_name=item.image_name,
                    old_path=old_path,
                    new_path=new_path,
                    old_thumbnail_path=old_thumbnail_path,
                    new_thumbnail_path=new_thumbnail_path,
                )
                return
            raise RuntimeError(f"Neither old nor new image file exists for {item.image_name}")

        old_thumbnail_exists = old_thumbnail_path.exists()
        new_thumbnail_exists = new_thumbnail_path.exists()
        if (
            old_exists
            and not new_exists

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Manually inspect and delete the stale duplicate (usually the old-path copy is the leftover; verify checksums against the DB record first) then re-run startup_recovery / complete_partial_filesystem_moves.
  2. Check job item state in image_subfolder_move_items; if the item is already 'moved', remove the duplicate old file rather than re-running the move.
  3. If the new file is corrupt/truncated from an interrupted copy, delete the new file so only old_exists and let the move re-execute.
  4. Restore the directory from backup to a consistent single-copy state, then re-run the move job.

Example fix

// before (ambiguous state, move aborts)
# images/old/abc.png AND images/new/abc.png both present
// after (resolve duplicate, keep the verified good copy)
# verify checksums, then:
rm images/old/abc.png
rm images/old/abc.webp  # stale thumbnail if present
# re-run recovery
invokeai-move-recovery  # or service.complete_partial_filesystem_moves(job_id)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
old = Path(old_subfolder_dir) / image_name
new = Path(new_subfolder_dir) / image_name
if old.exists() and new.exists():
    raise RuntimeError(f"resolve duplicate before completing move: {image_name}")

Type guard

def has_no_duplicate_move(old: Path, new: Path) -> bool:
    return not (old.exists() and new.exists())

Try / catch

try:
    service.complete_partial_filesystem_moves(job_id)
except RuntimeError as e:
    if "Both old and new image files exist" in str(e):
        # resolve the duplicate manually, then re-run
        ...

Prevention

When it happens

Trigger: Completing a partially-applied subfolder move (complete_partial_filesystem_moves) where a previous run already copied/moved the image to item.new_subfolder but the source at old_subfolder was not removed (e.g. a crash between copy and delete, or a manual re-copy of the file into the old location).

Common situations: Crash or power loss mid-move leaving duplicate files; a user manually copying the image back to its original folder after a partial move; running the move job twice with a strategy that resolved the same destination; backups/restores that recreate the old path.

Related errors


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