HMCL-dev/HMCL · error · ArtifactMalformedException

Malformed forge installer file, install_profile.json does…

Error message

Malformed forge installer file, install_profile.json does not exist.

What it means

ForgeOldInstallTask.execute() opens the legacy Forge installer jar as a ZipFile and requires an install_profile.json entry. If getEntry("install_profile.json") returns null (no stream), ArtifactMalformedException("Malformed forge installer file, install_profile.json does not exist.") is thrown — the file is not a legacy Forge universal/installer jar at all.

Solutions

  1. Re-download the correct '-installer.jar' artifact (not the universal jar) from files.minecraftforge.net
  2. Verify install_profile.json exists inside the jar: 'unzip -l forge-installer.jar | grep install_profile'
  3. Update HMCL — newer builds route new-format installers to ForgeNewInstallTask
  4. Clear the download cache so a stale/wrong cached installer is not reused
Defensive patterns

Strategy: validation

Validate before calling

// confirm this is a legacy installer containing install_profile.json
try (var zip = new java.util.zip.ZipFile(installer.toFile())) {
    if (zip.getEntry("install_profile.json") == null)
        throw new IllegalStateException("not a legacy forge installer");
}

Try / catch

try { installTask.execute(); } catch (ArtifactMalformedException e) { if (e.getMessage().contains("install_profile.json")) { downloadCorrectInstallerArtifact(); } else throw e; }

Prevention

When it happens

Trigger: installer path passed to ForgeOldInstallTask points to a zip/jar lacking install_profile.json — e.g. a Forge universal jar, a 'installer-win' variant with different layout, or a new-format installer handled by the wrong task; also plain corrupt files that still open as zip.

Common situations: Downloaded the wrong artifact (universal instead of installer) from the Forge file server; mirror served an error page that happens to be a zip; HMCL routed a new-format installer (install_title metadata) to the old installer path; user manually swapped the cached file.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java:73

        setSignificance(TaskSignificance.MAJOR);
    }

    @Override
    public List<Task<?>> getDependencies() {
        return dependencies;
    }

    @Override
    public boolean doPreExecute() {
        return true;
    }

    @Override
    public void execute() throws Exception {
        try (ZipFile zipFile = new ZipFile(installer.toFile())) {
            InputStream stream = zipFile.getInputStream(zipFile.getEntry("install_profile.json"));
            if (stream == null)
                throw new ArtifactMalformedException("Malformed forge installer file, install_profile.json does not exist.");
            ForgeInstallProfile installProfile = JsonUtils.fromNonNullJsonFully(stream, ForgeInstallProfile.class);

            // unpack the universal jar in the installer file.
            Library forgeLibrary = new Library(installProfile.install().getPath());
            GameRepository gameRepository = dependencyManager.getGameRepository();
            Path forgeFile = gameRepository.getLayout().getLibraryFile(manifest.id(), forgeLibrary);
            Files.createDirectories(forgeFile.getParent());

            ZipEntry forgeEntry = zipFile.getEntry(installProfile.install().getFilePath());
            try (InputStream is = zipFile.getInputStream(forgeEntry);
                 OutputStream os = Files.newOutputStream(forgeFile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
                is.transferTo(os);
            }

            setResult(GameInstancePatch.fromManifest(
                    installProfile.versionInfo(),
                    GameComponentType.FORGE.getPatchId(),
                    selfVersion,

View on GitHub (pinned to 24702dc5a0)