{"record":{"id":"ef253e5f0f61813c","repo":"HMCL-dev/HMCL","slug":"an-unregistered-instance-directory-already-exists","errorCode":null,"errorMessage":"An unregistered instance directory already exists","messagePattern":"An unregistered instance directory already exists","errorType":"exception","errorClass":"FileAlreadyExistsException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepositoryDraft.java","lineNumber":222,"sourceCode":"    /// Updates one manifest in the in-memory write set.\n    ///\n    /// @param manifest     the manifest to retain\n    /// @param claimNewRoot whether a previously absent instance root should become draft-owned\n    /// @throws IOException if a new instance root cannot be reserved\n    private void putManifest(\n            GameInstanceManifest manifest,\n            boolean claimNewRoot) throws IOException {\n\n        GameInstanceID id = manifest.id();\n        if (claimNewRoot\n                && !manifests.containsKey(id)\n                && baseSnapshot.get(id) == null\n                && !createdIds.contains(id)) {\n            Path root = baseSnapshot.getLayout().getInstanceRoot(id)\n                    .toAbsolutePath()\n                    .normalize();\n            if (!Files.notExists(root)) {\n                throw new FileAlreadyExistsException(root.toString(), null,\n                        \"An unregistered instance directory already exists\");\n            }\n            createdIds.add(id);\n        }\n\n        manifests.put(id, manifest);\n        removedIds.remove(id);\n        modifiedIds.add(id);\n    }\n\n    /// {@inheritDoc}\n    @Override\n    public DefaultGameRepositorySnapshot commit() throws IOException {\n        checkOpen();\n        repository.checkActiveDraft(this);\n        state = GameRepositoryDraft.State.COMMITTING;\n\n        List<RenameOperation> appliedRenames = new ArrayList<>();","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepositoryDraft.java#L204-L240","documentation":"putManifest() validates new instance ids before accepting them: if the id is not in the base snapshot and not already created by this draft, it is treated as a brand-new instance and its directory must not exist on disk. If a directory is already present at the instance root, it throws FileAlreadyExistsException with the message 'An unregistered instance directory already exists' — HMCL will not silently adopt or overwrite an unregistered folder.","triggerScenarios":"Calling draft.put(...) (or putManifest via rename) with an id whose instance directory already exists on disk but which is not registered in the repository — the folder exists but has no known manifest.","commonSituations":"Creating an instance with the same name as a previously deleted (but not fully removed) instance; users placing raw version folders into the instances directory manually; a prior failed create that left the directory behind; case-insensitive filesystems making ids appear distinct but collide on disk.","solutions":["Remove or rename the existing unregistered directory at the instance root before calling put","Pick a different, non-colliding instance id for the new instance","If the existing folder is a valid instance you want to keep, load/import it through the repository instead of creating a new one with the same id","Catch FileAlreadyExistsException, inspect the path in the message, and either clean it up or surface a 'name already in use' prompt to the user"],"exampleFix":"// before\ntry (Draft d = repo.openDraft()) {\n    d.put(id, manifest); // FileAlreadyExistsException if dir exists\n}\n// after\nPath root = repo.getLayout().getInstanceRoot(id);\nif (Files.exists(root)) {\n    throw new IllegalArgumentException(\"Instance name in use, pick another: \" + id);\n}\ntry (Draft d = repo.openDraft()) {\n    d.put(id, manifest);\n}","handlingStrategy":"validation","validationCode":"Path root = layout.getInstanceRoot(id).toAbsolutePath().normalize();\nif (Files.exists(root)) {\n    throw new IllegalArgumentException(\"Directory already exists for id: \" + id);\n}","typeGuard":null,"tryCatchPattern":"try {\n    draft.put(id, manifest);\n} catch (FileAlreadyExistsException e) {\n    LOG.warning(\"Unregistered directory in the way: \" + e.getFile());\n    // ask user to clean up or choose another id\n}","preventionTips":["Clean up directories left by failed creations","Avoid reusing ids of previously deleted instances without checking the disk","Import existing folders through the repository instead of re-creating over them"],"tags":["file-already-exists","create-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"}