HMCL-dev/HMCL · error · ArtifactMalformedException

Malformed neoforge installer file

Error message

Malformed neoforge installer file

What it means

Thrown when extracting files from the NeoForge installer zip during execute(): a ZipException means the installer is not a valid or complete ZIP archive. The file was fetched (or is local) but cannot be opened reliably for processor inputs.

Solutions

  1. Re-download the NeoForge installer from an official source and retry.
  2. Verify the installer opens as a zip (e.g. CompressingUtils.readZipFully / opening in an archive tool).
  3. Free disk space and disable interfering proxies/AV, then retry.

Example fix

// before
catch (ZipException ex) {
    throw new ArtifactMalformedException("Malformed neoforge installer file", ex);
}
// after
if (!CompressingUtils.checkZip(installer)) {
    throw new ArtifactMalformedException("Malformed neoforge installer file, please re-download", null);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!CompressingUtils.checkZip(installerPath)) {
    Files.deleteIfExists(installerPath);
    throw new IOException("NeoForge installer is not a valid zip");
}

Try / catch

try {
    await(task);
} catch (ArtifactMalformedException e) {
    Files.deleteIfExists(installerPath);
    await(task); // re-download and retry once
}

Prevention

When it happens

Trigger: Opening the installer with a zip filesystem and copying entries fails with ZipException — corrupted/partial download, an HTML error page stored as installer.jar, or a truncated local file the user pointed at.

Common situations: Interrupted downloads, unstable mirrors, wrong file selected manually in a 'import local installer' flow, antivirus quarantining part of the file.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeOldInstallTask.java:406

        FileUtils.copyFile(minecraftJar, isolatedMinecraftJar);

        Map<String, String> vars = new HashMap<>();

        try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(installer)) {
            for (Map.Entry<String, String> entry : profile.getData().entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();

                vars.put(key, parseLiteral(value,
                        Collections.emptyMap(),
                        str -> {
                            Path dest = Files.createTempFile(tempDir, null, null);
                            FileUtils.copyFile(fs.getPath(str), dest);
                            return dest.toString();
                        }));
            }
        } catch (ZipException ex) {
            throw new ArtifactMalformedException("Malformed neoforge installer file", ex);
        }

        vars.put("SIDE", "client");
        vars.put("MINECRAFT_JAR", FileUtils.getAbsolutePath(isolatedMinecraftJar));
        vars.put("MINECRAFT_VERSION", profile.getMinecraft());
        vars.put("ROOT", FileUtils.getAbsolutePath(gameRepository.getBaseDirectory()));
        vars.put("INSTALLER", installer.toAbsolutePath().toString());
        vars.put("LIBRARY_DIR", FileUtils.getAbsolutePath(gameRepository.getLayout().getLibrariesDirectory()));

        updateProgress(0, processors.size());

        Task<?> processorsTask = Task.runSequentially(
                processors.stream()
                        .map(processor -> createProcessorTask(processor, vars))
                        .toArray(Task<?>[]::new));

        dependencies.add(
                processorsTask.thenComposeAsync(

View on GitHub (pinned to 24702dc5a0)