{"record":{"id":"25bbbe752b374bb6","repo":"HMCL-dev/HMCL","slug":"instance-directory-does-not-exist-sourceroot","errorCode":null,"errorMessage":"Instance directory does not exist: ${sourceRoot}","messagePattern":"Instance directory does not exist: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepositoryDraft.java","lineNumber":493,"sourceCode":"        Path parent = baseSnapshot.getLayout().getBaseDirectory()\n                .toAbsolutePath()\n                .normalize()\n                .resolve(\".hmcl\")\n                .resolve(\"repository-drafts\");\n        Files.createDirectories(parent);\n        return Files.createTempDirectory(parent, \"commit-\");\n    }\n\n    /// Applies one instance directory rename.\n    ///\n    /// @param rename  the requested rename\n    /// @param applied rollback records for completed renames\n    /// @throws IOException if the source files cannot be renamed\n    private void applyRename(RenameOperation rename, List<RenameOperation> applied) throws IOException {\n        Path sourceRoot = baseSnapshot.getLayout().getInstanceRoot(rename.from());\n        Path targetRoot = baseSnapshot.getLayout().getInstanceRoot(rename.to());\n        if (!Files.isDirectory(sourceRoot)) {\n            throw new IOException(\"Instance directory does not exist: \" + sourceRoot);\n        }\n        if (Files.exists(targetRoot)) {\n            throw new FileAlreadyExistsException(targetRoot.toString());\n        }\n\n        DefaultGameRepository.moveInstanceFiles(\n                baseSnapshot.getLayout().getBaseDirectory(),\n                rename.from(),\n                rename.to());\n        applied.add(rename);\n    }\n\n    /// Moves one removed instance root into the commit rollback directory.\n    ///\n    /// @param id                the removed instance id\n    /// @param rollbackDirectory the directory owned by the current commit attempt\n    /// @param removed           rollback records for roots moved out of the repository\n    /// @throws IOException if the root cannot be moved into the rollback directory","sourceCodeStart":475,"sourceCodeEnd":511,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepositoryDraft.java#L475-L511","documentation":"DefaultGameRepositoryDraft.applyRename throws this IOException when the source directory of a rename (instance rename) operation does not exist on disk. commit() invokes applyRename to move instance files from rename.from() to rename.to(); the check guards that the move has a real source. It indicates repository state on disk diverges from the in-memory draft.","triggerScenarios":"commit() with a RenameOperation whose 'from' instance directory was deleted, renamed externally, or never existed — i.e. baseSnapshot.getLayout().getInstanceRoot(rename.from()) is not a directory.","commonSituations":"Another process/user deleted or moved the instance folder while the launcher ran; committing a rename twice; renaming an instance whose directory creation failed earlier.","solutions":["Verify the source directory exists (Files.isDirectory(instanceRoot)) before committing the rename","Re-sync the repository snapshot (reload instances) so the draft matches disk state","Skip or drop the stale rename operation from the commit batch","Restore the missing directory from backup or recreate the instance"],"exampleFix":"// before\nrepo.commit(draft); // draft contains rename of deleted instance\n// after\nif (Files.isDirectory(repo.getInstanceRoot(id))) {\n    repo.commit(draft);\n} else {\n    draft.dropRename(id);\n    repo.commit(draft);\n}","handlingStrategy":"validation","validationCode":"Path src = baseSnapshot.getLayout().getInstanceRoot(rename.from());\nif (!Files.isDirectory(src)) { /* skip rename or resync snapshot */ }","typeGuard":"static boolean renameSourceExists(DefaultGameRepositorySnapshot s, GameInstanceID from) {\n    return Files.isDirectory(s.getLayout().getInstanceRoot(from));\n}","tryCatchPattern":"try { repo.commit(draft); }\ncatch (IOException e) { if (e.getMessage().startsWith(\"Instance directory does not exist\")) { repo.reload(); } else throw e; }","preventionTips":["Check Files.isDirectory on the source root before committing renames","Reload the repository snapshot after external filesystem changes","Avoid committing multiple renames of the same instance in one batch"],"tags":["io","filesystem","rename"],"backgroundTag":"directory-not-found","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"}