HMCL-dev/HMCL · error · IOException

Instance directory does not exist

Error message

Instance directory does not exist: ${sourceRoot}

What it means

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.

Solutions

  1. Verify the source directory exists (Files.isDirectory(instanceRoot)) before committing the rename
  2. Re-sync the repository snapshot (reload instances) so the draft matches disk state
  3. Skip or drop the stale rename operation from the commit batch
  4. Restore the missing directory from backup or recreate the instance

Example fix

// before
repo.commit(draft); // draft contains rename of deleted instance
// after
if (Files.isDirectory(repo.getInstanceRoot(id))) {
    repo.commit(draft);
} else {
    draft.dropRename(id);
    repo.commit(draft);
}
Defensive patterns

Strategy: validation

Validate before calling

Path src = baseSnapshot.getLayout().getInstanceRoot(rename.from());
if (!Files.isDirectory(src)) { /* skip rename or resync snapshot */ }

Type guard

static boolean renameSourceExists(DefaultGameRepositorySnapshot s, GameInstanceID from) {
    return Files.isDirectory(s.getLayout().getInstanceRoot(from));
}

Try / catch

try { repo.commit(draft); }
catch (IOException e) { if (e.getMessage().startsWith("Instance directory does not exist")) { repo.reload(); } else throw e; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10). Data as JSON: /api/errors/25bbbe752b374bb6. Report an issue: GitHub.

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepositoryDraft.java:493

        Path parent = baseSnapshot.getLayout().getBaseDirectory()
                .toAbsolutePath()
                .normalize()
                .resolve(".hmcl")
                .resolve("repository-drafts");
        Files.createDirectories(parent);
        return Files.createTempDirectory(parent, "commit-");
    }

    /// Applies one instance directory rename.
    ///
    /// @param rename  the requested rename
    /// @param applied rollback records for completed renames
    /// @throws IOException if the source files cannot be renamed
    private void applyRename(RenameOperation rename, List<RenameOperation> applied) throws IOException {
        Path sourceRoot = baseSnapshot.getLayout().getInstanceRoot(rename.from());
        Path targetRoot = baseSnapshot.getLayout().getInstanceRoot(rename.to());
        if (!Files.isDirectory(sourceRoot)) {
            throw new IOException("Instance directory does not exist: " + sourceRoot);
        }
        if (Files.exists(targetRoot)) {
            throw new FileAlreadyExistsException(targetRoot.toString());
        }

        DefaultGameRepository.moveInstanceFiles(
                baseSnapshot.getLayout().getBaseDirectory(),
                rename.from(),
                rename.to());
        applied.add(rename);
    }

    /// Moves one removed instance root into the commit rollback directory.
    ///
    /// @param id                the removed instance id
    /// @param rollbackDirectory the directory owned by the current commit attempt
    /// @param removed           rollback records for roots moved out of the repository
    /// @throws IOException if the root cannot be moved into the rollback directory

View on GitHub (pinned to 24702dc5a0)