HMCL-dev/HMCL · error · IOException

Not a valid MultiMC modpack

Error message

Not a valid MultiMC modpack

What it means

Same family as the task-side check but applied while reading the modpack zip: getRootEntryName scans top-level entries to locate the directory containing the instance files (mmc-pack.json etc.) and throws if none qualifies, meaning the archive does not match the MultiMC modpack layout.

Solutions

  1. Ensure the archive root or a single top-level folder contains mmc-pack.json.
  2. Select the correct modpack type in the import dialog if the pack is CurseForge/Modrinth format.
  3. Re-export the instance from MultiMC/Prism Launcher.

Example fix

// before
/backup/old/instance/mmc-pack.json  -> deeper than one level
// after
/my-modpack/mmc-pack.json           -> detected correctly
Defensive patterns

Strategy: validation

Validate before calling

try (ZipArchiveReader r = new ZipArchiveReader(zip)) {
    boolean ok = r.getEntries().stream().anyMatch(e ->
        e.getName().equals("mmc-pack.json") || e.getName().matches("[^/]+/mmc-pack.json"));
}

Try / catch

try { Modpack m = provider.readManifest(reader, zipPath, encoding); } catch (IOException e) { if (e.getMessage().equals("Not a valid MultiMC modpack")) { /* try another provider */ } }

Prevention

When it happens

Trigger: MultiMCModpackProvider.getRootEntryName(modpackFile) finds no zip entry whose name ends with the instance file name (mmc-pack.json) at a top-level directory, e.g. during Modpack detection/readManifest.

Common situations: Importing a random zip (not a MultiMC pack) via the MultiMC provider; nested archives (zip inside zip); instance folder more than one level deep.

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/8da65ae21f41989b. Report an issue: GitHub.

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/modpack/multimc/MultiMCModpackProvider.java:74

        return new ModpackUpdateTask(instance, new MultiMCModpackInstallTask(dependencyManager, zipFile, modpack, multiMCInstanceConfiguration, instance));
    }

    private static String getRootEntryName(ZipArchiveReader file) throws IOException {
        final String instanceFileName = "instance.cfg";

        if (file.getEntry(instanceFileName) != null) return "";

        for (ZipArchiveEntry entry : file.getEntries()) {
            String entryName = entry.getName();

            int idx = entryName.indexOf('/');
            if (idx >= 0
                    && entryName.length() == idx + instanceFileName.length() + 1
                    && entryName.startsWith(instanceFileName, idx + 1))
                return entryName.substring(0, idx + 1);
        }

        throw new IOException("Not a valid MultiMC modpack");
    }

    @Override
    public Modpack readManifest(ZipArchiveReader modpackFile, Path modpackPath, Charset encoding) throws IOException {
        String rootEntryName = getRootEntryName(modpackFile);
        MultiMCManifest manifest = MultiMCManifest.readMultiMCModpackManifest(modpackFile, rootEntryName);

        String name = rootEntryName.isEmpty() ? FileUtils.getNameWithoutExtension(modpackPath) : rootEntryName.substring(0, rootEntryName.length() - 1);
        ZipArchiveEntry instanceEntry = modpackFile.getEntry(rootEntryName + "instance.cfg");

        if (instanceEntry == null)
            throw new IOException("`instance.cfg` not found, " + modpackFile + " is not a valid MultiMC modpack.");
        try (InputStream instanceStream = modpackFile.getInputStream(instanceEntry)) {
            MultiMCInstanceConfiguration cfg = new MultiMCInstanceConfiguration(name, instanceStream, manifest);
            return new Modpack(cfg.getName(), "", "", cfg.getGameVersion(), cfg.getNotes(), encoding, cfg) {
                @Override
                public Task<?> getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, GameInstanceID instanceId, String iconUrl) {
                    return new MultiMCModpackInstallTask(dependencyManager, zipFile, this, cfg, instanceId);

View on GitHub (pinned to 24702dc5a0)