HMCL-dev/HMCL · error · Exception

Game processor jar does not have main class

Error message

Game processor jar does not have main class 

What it means

Thrown when the processor JAR exists but its manifest has no Main-Class attribute (or it is blank). HMCL launches each Forge processor via 'java -cp <jar> <mainClass>'; without a main class in the manifest it cannot determine what to execute. It is a plain Exception propagated out of ProcessorTask.execute().

Solutions

  1. Delete the corrupt processor jar from the libraries directory and re-run installation to re-download it
  2. Verify the jar opens with 'jar tf' and its MANIFEST.MF has a Main-Class entry
  3. Check the downloaded file's size/SHA-1 against the Forge maven metadata
  4. Exclude the game directory from antivirus interference and retry

Example fix

// before: blindly trusting a 0-byte jar
Path jar = Paths.get("libraries/net/minecraftforge/installertools/1.3.0/installertools-1.3.0.jar");
// after: sanity-check before running install task
if (Files.size(jar) < 1024) {
    Files.delete(jar); // force re-download
}
new ForgeNewInstallTask(dependencyManager, manifest, minecraftJar, version, installer);
Defensive patterns

Strategy: validation

Validate before calling

// Verify processor jars are real, executable jars before install
try (JarFile jf = new JarFile(jarPath.toFile())) {
    String mc = jf.getManifest() == null ? null : jf.getManifest().getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
    if (mc == null || mc.isBlank()) { Files.delete(jarPath); throw new IOException("Bad processor jar, re-download"); }
}

Try / catch

try {
    installTask.run();
} catch (Exception e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Game processor jar does not have main class")) {
        // delete the jar and re-download libraries, then retry
    }
}

Prevention

When it happens

Trigger: The processor jar file in the repository is corrupted, empty, or not an executable jar (e.g. an HTML error page saved as .jar, a truncated download, or a jar-repack that dropped META-INF/MANIFEST.MF).

Common situations: Proxy/CDN serving an error page in place of the jar; interrupted download leaving a zero-byte file; antivirus quarantining and rewriting jar files.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java:122

                    miss = true;
                }
            }

            if (!processor.getOutputs().isEmpty() && !miss) {
                return;
            }

            Path jar = gameRepository.getLayout().getArtifactFile(processor.getJar());
            if (!Files.isRegularFile(jar))
                throw new FileNotFoundException("Game processor file not found, should be downloaded in preprocess");

            String mainClass;
            try (JarFile jarFile = new JarFile(jar.toFile())) {
                mainClass = jarFile.getManifest().getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
            }

            if (StringUtils.isBlank(mainClass))
                throw new Exception("Game processor jar does not have main class " + jar);

            List<String> command = new ArrayList<>();
            command.add(JavaRuntime.getDefault().getBinary().toString());
            command.add("-cp");

            List<String> classpath = new ArrayList<>(processor.getClasspath().size() + 1);
            for (Artifact artifact : processor.getClasspath()) {
                Path file = gameRepository.getLayout().getArtifactFile(artifact);
                if (!Files.isRegularFile(file))
                    throw new Exception("Game processor dependency missing");
                classpath.add(file.toString());
            }
            classpath.add(jar.toString());
            command.add(String.join(File.pathSeparator, classpath));

            command.add(mainClass);

            List<String> args = new ArrayList<>(processor.getArgs().size());

View on GitHub (pinned to 24702dc5a0)