{"record":{"id":"eb1c4ec3b4dcea99","repo":"invoke-ai/InvokeAI","slug":"destination-thumbnail-already-exists-move-new-th","errorCode":null,"errorMessage":"Destination thumbnail already exists: {move.new_thumbnail_path}","messagePattern":"Destination thumbnail already exists: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"invokeai/app/services/image_moves/image_moves_default.py","lineNumber":449,"sourceCode":"                if not move.is_intermediate:\n                    raise FileNotFoundError(f\"Source image does not exist: {move.old_path}\")\n                continue\n            if move.new_path.exists():\n                raise FileExistsError(f\"Destination image already exists: {move.new_path}\")\n            if move.old_path == move.new_path:\n                raise ValueError(f\"Old and new paths are identical for {move.image_name}\")\n            if move.new_path in destinations:\n                raise ValueError(f\"Duplicate destination path: {move.new_path}\")\n            destinations.add(move.new_path)\n            if move.new_thumbnail_path in thumbnail_destinations:\n                raise ValueError(f\"Duplicate destination thumbnail path: {move.new_thumbnail_path}\")\n            thumbnail_destinations.add(move.new_thumbnail_path)\n            if self._has_active_job_for_image(move.image_name):\n                raise ValueError(f\"Image {move.image_name} already has an active image move job\")\n            self._assert_same_filesystem(move.old_path, move.new_path)\n            if move.old_thumbnail_path.exists():\n                if move.new_thumbnail_path.exists():\n                    raise FileExistsError(f\"Destination thumbnail already exists: {move.new_thumbnail_path}\")\n                self._assert_same_filesystem(move.old_thumbnail_path, move.new_thumbnail_path)\n\n    def _record_missing_source_errors(self, moves: Sequence[PlannedImageMove]) -> tuple[list[PlannedImageMove], int]:\n        remaining_moves: list[PlannedImageMove] = []\n        errors = 0\n        for move in moves:\n            if move.old_path.exists() or move.is_intermediate:\n                remaining_moves.append(move)\n                continue\n            message = f\"Source image does not exist: {move.old_path}\"\n            self.create_error_move_job(move, message)\n            self._logger.error(message)\n            errors += 1\n        return remaining_moves, errors\n\n    def perform_filesystem_moves(self, job_id: int) -> None:\n        self._set_job_state(job_id, \"moving\")\n        self.complete_partial_filesystem_moves(job_id)","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/image_moves/image_moves_default.py#L431-L467","documentation":"When an image's existing thumbnail file is being moved, its destination thumbnail path must be free. preflight_moves raises FileExistsError if old_thumbnail_path exists but new_thumbnail_path already exists, guarding against clobbering another image's thumbnail.","triggerScenarios":"Re-running a move whose thumbnails were already copied; two images whose thumbnail names collide and one already exists on disk; destination thumbnail folder seeded with same-named files.","commonSituations":"Interrupted prior move leaving thumbnails in place; shared thumbnail directory with name collisions; case-insensitive filesystems colliding thumbnail names.","solutions":["Complete the earlier job via startup_recovery/complete_partial_filesystem_moves instead of re-planning","Delete or rename the pre-existing destination thumbnail if it's stale","Pick a different destination so thumbnail names don't collide","Skip images whose thumbnails were already migrated in the caller"],"exampleFix":"// before\nservice.preflight_moves(moves)\n// after\nmoves = [m for m in moves if not (m.old_thumbnail_path.exists() and m.new_thumbnail_path.exists())]\nservice.preflight_moves(moves)","handlingStrategy":"validation","validationCode":"clashes = [m for m in moves if m.old_thumbnail_path.exists() and m.new_thumbnail_path.exists()]\nif clashes:\n    raise FileExistsError(f\"destination thumbnails exist: {[str(m.new_thumbnail_path) for m in clashes]}\")\nservice.preflight_moves(moves)","typeGuard":"def thumbnail_destination_free(move: PlannedImageMove) -> bool:\n    return not (move.old_thumbnail_path.exists() and move.new_thumbnail_path.exists())","tryCatchPattern":"try:\n    service.preflight_moves(moves)\nexcept FileExistsError as e:\n    if \"Destination thumbnail\" in str(e):\n        clean_or_relocate_stale_thumbnail(e)\n        service.preflight_moves(moves)\n    else:\n        raise","preventionTips":["Complete interrupted jobs via recovery instead of re-planning from scratch","Keep thumbnails in a per-image-unique layout","Watch for case-insensitive filesystem collisions in thumbnail names"],"tags":["filesystem","file-exists","thumbnail","image-move"],"backgroundTag":"destination-already-exists","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}