{"record":{"id":"9129e86a6a244fc1","repo":"HMCL-dev/HMCL","slug":"targetroot","errorCode":null,"errorMessage":"${targetRoot}","messagePattern":"\\$\\{targetRoot\\}","errorType":"exception","errorClass":"FileAlreadyExistsException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepositoryDraft.java","lineNumber":175,"sourceCode":"\n    /// {@inheritDoc}\n    @Override\n    public void rename(GameInstanceID from, GameInstanceID to) throws IOException {\n        checkOpen();\n        @Nullable GameInstanceManifest source = manifests.get(from);\n        if (source == null) {\n            throw new NoSuchGameInstanceException(from);\n        }\n        if (createdIds.contains(from)) {\n            throw new IllegalStateException(\"Cannot rename an instance created by the same draft\");\n        }\n        if (manifests.containsKey(to)) {\n            throw new IllegalArgumentException(\"Target instance already exists: \" + to);\n        }\n\n        Path targetRoot = baseSnapshot.getLayout().getInstanceRoot(to);\n        if (Files.exists(targetRoot)) {\n            throw new FileAlreadyExistsException(targetRoot.toString());\n        }\n\n        GameInstanceManifest renamedManifest = source;\n        if (from.equals(renamedManifest.jar())) {\n            renamedManifest = renamedManifest.withJar(null);\n        }\n        renamedManifest = renamedManifest.withId(to);\n\n        manifests.remove(from);\n        modifiedIds.remove(from);\n        removedIds.remove(from);\n        putManifest(renamedManifest, false);\n\n        @Nullable Path primaryJarSource = primaryJarSources.remove(from);\n        if (primaryJarSource != null) {\n            primaryJarSources.put(to, primaryJarSource);\n        }\n","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepositoryDraft.java#L157-L193","documentation":"During rename, the draft computes the target instance directory via the layout (getInstanceRoot(to)) and refuses to overwrite anything on disk: if a directory already exists at targetRoot, it throws FileAlreadyExistsException with that path (message '${targetRoot}'). This protects an existing instance's files from being clobbered by a rename.","triggerScenarios":"Renaming an instance to an id whose directory already exists under the repository root — e.g. the target id was previously used and left orphaned files on disk, even though it is not registered in the manifests map (which is why the earlier containsKey check passed).","commonSituations":"A previously deleted instance whose folder removal failed or was done outside HMCL; users manually creating folders in .minecraft/versions (or the repo root) with instance names; renaming to a name that collides with an unregistered leftover directory.","solutions":["Delete or move the existing directory at targetRoot before renaming, after confirming it holds no needed files","Choose a different target instance id that does not collide with an existing folder","Catch FileAlreadyExistsException and surface the path so the user can clean it up manually","Clean up orphaned instance directories periodically so renames do not hit leftover folders"],"exampleFix":"// before\ndraft.rename(from, GameInstanceID.of(\"1.8.9\")); // may throw FileAlreadyExistsException\n// after\nPath targetRoot = repo.getLayout().getInstanceRoot(newId);\nif (Files.exists(targetRoot)) {\n    Files.move(targetRoot, targetRoot.resolveSibling(targetRoot.getFileName() + \".bak\"));\n}\ndraft.rename(from, newId);","handlingStrategy":"try-catch","validationCode":"Path targetRoot = layout.getInstanceRoot(to);\nif (Files.exists(targetRoot)) {\n    throw new IllegalArgumentException(\"Target dir exists: \" + targetRoot);\n}","typeGuard":null,"tryCatchPattern":"try {\n    draft.rename(from, to);\n} catch (FileAlreadyExistsException e) {\n    LOG.warning(\"Rename blocked, target directory exists: \" + e.getFile());\n    // prompt user to clean up or pick another name\n}","preventionTips":["Clean orphaned instance directories after failed deletes","Check the filesystem (not just the manifest map) for target collisions","Generate unique instance ids rather than reusing old names"],"tags":["file-already-exists","rename-conflict","minecraft-instance"],"backgroundTag":"file-already-exists","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}