{"record":{"id":"fdb7e771d092befb","repo":"invoke-ai/InvokeAI","slug":"duplicate-destination-path-move-new-path","errorCode":null,"errorMessage":"Duplicate destination path: {move.new_path}","messagePattern":"Duplicate destination path: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"invokeai/app/services/image_moves/image_moves_default.py","lineNumber":439,"sourceCode":"                    message,\n                ),\n            )\n            return job_id\n\n    def preflight_moves(self, moves: Sequence[PlannedImageMove]) -> None:\n        destinations: set[Path] = set()\n        thumbnail_destinations: set[Path] = set()\n        for move in moves:\n            if not move.old_path.exists():\n                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)","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/image_moves/image_moves_default.py#L421-L457","documentation":"Two moves within the same planned batch must not target the same destination path. preflight_moves accumulates destinations in a set and raises ValueError on the second move targeting an already-claimed new_path, since only one source can occupy a destination.","triggerScenarios":"A batch where two images (e.g. duplicates or name-colliding images in different folders) are planned into the same target directory with the same filename; programmatic construction of PlannedImageMove lists that reuses a destination.","commonSituations":"Merging several subfolders into one folder where image names collide; copying images across boards with duplicate names into a shared target; generating moves without de-duplicating destinations.","solutions":["De-duplicate or rename destination paths when building the moves list (e.g. append a numeric suffix on collision)","Split the batch so colliding images move to different destinations","Detect collisions up front in the caller using a set of new_path values"],"exampleFix":"// before\nmoves = [plan(img, dest) for img in images]  # may collide\n// after\nseen = set()\nmoves = [plan(img, uniquify(dest, seen)) for img in images]\nservice.preflight_moves(moves)","handlingStrategy":"validation","validationCode":"dests = [m.new_path for m in moves]\ndupes = {d for d in dests if dests.count(d) > 1}\nif dupes:\n    raise ValueError(f\"duplicate destinations: {dupes}\")\nservice.preflight_moves(moves)","typeGuard":"def destinations_unique(moves: Sequence[PlannedImageMove]) -> bool:\n    return len({m.new_path for m in moves}) == len(moves)","tryCatchPattern":"try:\n    service.preflight_moves(moves)\nexcept ValueError as e:\n    if \"Duplicate destination path\" in str(e):\n        moves = uniquify_destinations(moves)  # suffix colliding names\n        service.preflight_moves(moves)\n    else:\n        raise","preventionTips":["De-duplicate destinations when building batches, especially when merging folders","Suffix colliding filenames with a counter or hash","Warn users when merging folders that contain identically named images"],"tags":["validation","image-move","duplicate","preflight"],"backgroundTag":"duplicate-destination-path","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}