HMCL-dev/HMCL · critical · IllegalStateException

Main class is null for instance

Error message

Main class is null for instance 

What it means

DefaultLauncher.generateCommandLine appends the game's main class from the version manifest; if manifest.mainClass() is null the launch command cannot be assembled, so it throws IllegalStateException("Main class is null for instance " + manifest.id()). This indicates a malformed or incomplete version JSON.

Solutions

  1. Fix the version JSON by adding the correct mainClass (e.g. net.minecraft.client.main.Main) for the version.
  2. Delete the version folder and let the launcher re-download the official version metadata.
  3. If using a custom version, base it on the complete official version JSON rather than editing from scratch.
  4. Verify manifest.id() matches the intended version so the right manifest is loaded.

Example fix

// before (version JSON)
// { "id": "1.20.1", "minecraftArguments": "..." }
// after
// { "id": "1.20.1", "mainClass": "net.minecraft.client.main.Main", "minecraftArguments": "..." }
Defensive patterns

Strategy: validation

Validate before calling

if (manifest.mainClass() == null) {
    // refuse to launch; repair the version JSON first
}

Try / catch

try {
    launcher.launch();
} catch (IllegalStateException e) {
    if (e.getMessage().startsWith("Main class is null")) {
        // re-download official version metadata for manifest.id()
    }
}

Prevention

When it happens

Trigger: Launching an instance whose version manifest (Version JSON) has no mainClass field — e.g. a hand-edited or truncated version file, or a manifest built from an incomplete metadata parse.

Common situations: Manually copying version JSONs between installs and dropping fields; corrupted version downloads; custom/third-party version JSONs missing mainClass; version id mismatch causing wrong manifest resolution.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java:354

                        }
                    }

                    break;
                }
            }
        }

        res.addAll(Arguments.parseArguments(Objects.requireNonNullElseGet(jvmArguments, this::getDefaultJVMArguments), configuration));
        Arguments argumentsFromAuthInfo = authInfo.getLaunchArguments(options);
        if (argumentsFromAuthInfo != null && argumentsFromAuthInfo.jvm() != null && !argumentsFromAuthInfo.jvm().isEmpty())
            res.addAll(Arguments.parseArguments(argumentsFromAuthInfo.jvm(), configuration));

        for (String javaAgent : options.getJavaAgents()) {
            res.add("-javaagent:" + javaAgent);
        }

        if (manifest.mainClass() == null) {
            throw new IllegalStateException("Main class is null for instance " + manifest.id());
        }

        res.add(manifest.mainClass());

        res.addAll(Arguments.parseStringArguments(Optional.ofNullable(manifest.minecraftArguments()).map(StringUtils::tokenize).orElseGet(ArrayList::new), configuration));

        Map<String, Boolean> features = getFeatures();
        Optional.ofNullable(manifest.arguments()).map(Arguments::game).ifPresent(arguments -> res.addAll(Arguments.parseArguments(arguments, configuration, features)));
        if (Optional.ofNullable(manifest.minecraftArguments()).isPresent()) {
            res.addAll(Arguments.parseArguments(this.getDefaultGameArguments(), configuration, features));
        }
        if (argumentsFromAuthInfo != null && argumentsFromAuthInfo.game() != null && !argumentsFromAuthInfo.game().isEmpty())
            res.addAll(Arguments.parseArguments(argumentsFromAuthInfo.game(), configuration, features));

        if (options.getQuickPlayOption() instanceof QuickPlayOption.MultiPlayer multiPlayer) {
            String address = multiPlayer.serverIP();

            try {

View on GitHub (pinned to 24702dc5a0)