HMCL-dev/HMCL · error · IllegalArgumentException

name existing

Error message

name existing

What it means

Thrown by getInstallManuallyCreatedModpackTask as an IllegalArgumentException when the requested name for a manually created modpack conflicts with an existing external game directory. The check is isExternalGameNameConflicts(name), which tests whether the 'externalgames/<name>' directory already exists on disk. HMCL refuses to install over an existing external game to avoid clobbering it.

Solutions

  1. Choose a different, unique name for the modpack instance
  2. Check isExternalGameNameConflicts(name) before installing and prompt the user for a new name
  3. If the old directory is unwanted, delete the externalgames/<name> directory first
  4. Verify no stale/orphaned directory from a previous failed install remains

Example fix

// before
Task<?> task = ModpackHelper.getInstallManuallyCreatedModpackTask(zip, "MyPack", charset);
// after
if (!ModpackHelper.isExternalGameNameConflicts("MyPack")) {
    Task<?> task = ModpackHelper.getInstallManuallyCreatedModpackTask(zip, "MyPack", charset);
} else {
    throw new IllegalStateException("Name 'MyPack' already in use; pick another name");
}
Defensive patterns

Strategy: validation

Validate before calling

if (ModpackHelper.isExternalGameNameConflicts(name)) {
    throw new IllegalStateException("Modpack name '" + name + "' is already in use");
}

Try / catch

try {
    Task<?> task = ModpackHelper.getInstallManuallyCreatedModpackTask(zipFile, name, charset);
} catch (IllegalArgumentException e) {
    ui.promptNameAlreadyExists(name); // ask user for another name
}

Prevention

When it happens

Trigger: Calling getInstallManuallyCreatedModpackTask(zipFile, name, charset) with a name such that Paths.get("externalgames").resolve(name) exists.

Common situations: User picks a modpack name identical to one already installed (or previously created) in the externalgames folder; leftover directory from a failed earlier install; re-running an install flow without changing the name; name differing only in characters that normalize to the same path.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java:184

        ExceptionalConsumer<Exception, ?> failure = ex -> {
            if (ex instanceof ModpackCompletionException && !(ex.getCause() instanceof FileNotFoundException)) {
                success.run();
                // This is tolerable and we will not delete the game
            }
        };

        return new ServerModpackRemoteInstallTask(repository.getDependency(), manifest, instanceId)
                .whenComplete(Schedulers.defaultScheduler(), success, failure)
                .withStagesHints(new Task.StagesHint("hmcl.modpack"), new Task.StagesHint("hmcl.modpack.download", List.of("hmcl.install.assets", "hmcl.install.libraries")));
    }

    public static boolean isExternalGameNameConflicts(String name) {
        return Files.exists(Paths.get("externalgames").resolve(name));
    }

    public static Task<?> getInstallManuallyCreatedModpackTask(Path zipFile, String name, Charset charset) {
        if (isExternalGameNameConflicts(name)) {
            throw new IllegalArgumentException("name existing");
        }

        return new ManuallyCreatedModpackInstallTask(zipFile, charset, name)
                .thenAcceptAsync(Schedulers.javafx(), location -> {
                    GameDirectory newGameDirectory = new GameDirectory(
                            GameDirectoryManager.newGameDirectoryId(),
                            LocalizedText.plain(name),
                            PortablePath.fromPath(location));
                    GameDirectoryManager.addLocalGameDirectory(newGameDirectory);
                    GameDirectoryManager.setSelectedGameDirectory(newGameDirectory);
                });
    }

    public static Task<?> getInstallTask(HMCLGameRepository repository, Path zipFile, GameInstanceID instanceId, Modpack modpack, @Nullable String iconUrl) {
        ExceptionalRunnable<?> success = () -> {
            repository.refresh();
            repository.getInstance(instanceId).enableIsolation();
        };

View on GitHub (pinned to 24702dc5a0)