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
- Fix the version JSON by adding the correct mainClass (e.g. net.minecraft.client.main.Main) for the version.
- Delete the version folder and let the launcher re-download the official version metadata.
- If using a custom version, base it on the complete official version JSON rather than editing from scratch.
- 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
- Never hand-edit version JSONs; derive custom versions from complete official ones
- Re-download version metadata if files were copied between installs
- Validate downloaded version JSON contains mainClass before caching
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
- Missing author name:
- Theme pack value is missing
- Theme ID is required when a theme pack declares multiple…
- Theme name is required when a theme pack declares multiple…
- Theme-pack manifest is missing
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)