{"record":{"id":"8da65ae21f41989b","repo":"HMCL-dev/HMCL","slug":"not-a-valid-multimc-modpack-8da65a","errorCode":null,"errorMessage":"Not a valid MultiMC modpack","messagePattern":"Not a valid MultiMC modpack","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/modpack/multimc/MultiMCModpackProvider.java","lineNumber":74,"sourceCode":"        return new ModpackUpdateTask(instance, new MultiMCModpackInstallTask(dependencyManager, zipFile, modpack, multiMCInstanceConfiguration, instance));\n    }\n\n    private static String getRootEntryName(ZipArchiveReader file) throws IOException {\n        final String instanceFileName = \"instance.cfg\";\n\n        if (file.getEntry(instanceFileName) != null) return \"\";\n\n        for (ZipArchiveEntry entry : file.getEntries()) {\n            String entryName = entry.getName();\n\n            int idx = entryName.indexOf('/');\n            if (idx >= 0\n                    && entryName.length() == idx + instanceFileName.length() + 1\n                    && entryName.startsWith(instanceFileName, idx + 1))\n                return entryName.substring(0, idx + 1);\n        }\n\n        throw new IOException(\"Not a valid MultiMC modpack\");\n    }\n\n    @Override\n    public Modpack readManifest(ZipArchiveReader modpackFile, Path modpackPath, Charset encoding) throws IOException {\n        String rootEntryName = getRootEntryName(modpackFile);\n        MultiMCManifest manifest = MultiMCManifest.readMultiMCModpackManifest(modpackFile, rootEntryName);\n\n        String name = rootEntryName.isEmpty() ? FileUtils.getNameWithoutExtension(modpackPath) : rootEntryName.substring(0, rootEntryName.length() - 1);\n        ZipArchiveEntry instanceEntry = modpackFile.getEntry(rootEntryName + \"instance.cfg\");\n\n        if (instanceEntry == null)\n            throw new IOException(\"`instance.cfg` not found, \" + modpackFile + \" is not a valid MultiMC modpack.\");\n        try (InputStream instanceStream = modpackFile.getInputStream(instanceEntry)) {\n            MultiMCInstanceConfiguration cfg = new MultiMCInstanceConfiguration(name, instanceStream, manifest);\n            return new Modpack(cfg.getName(), \"\", \"\", cfg.getGameVersion(), cfg.getNotes(), encoding, cfg) {\n                @Override\n                public Task<?> getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, GameInstanceID instanceId, String iconUrl) {\n                    return new MultiMCModpackInstallTask(dependencyManager, zipFile, this, cfg, instanceId);","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/modpack/multimc/MultiMCModpackProvider.java#L56-L92","documentation":"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.","triggerScenarios":"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.","commonSituations":"Importing a random zip (not a MultiMC pack) via the MultiMC provider; nested archives (zip inside zip); instance folder more than one level deep.","solutions":["Ensure the archive root or a single top-level folder contains mmc-pack.json.","Select the correct modpack type in the import dialog if the pack is CurseForge/Modrinth format.","Re-export the instance from MultiMC/Prism Launcher."],"exampleFix":"// before\n/backup/old/instance/mmc-pack.json  -> deeper than one level\n// after\n/my-modpack/mmc-pack.json           -> detected correctly","handlingStrategy":"validation","validationCode":"try (ZipArchiveReader r = new ZipArchiveReader(zip)) {\n    boolean ok = r.getEntries().stream().anyMatch(e ->\n        e.getName().equals(\"mmc-pack.json\") || e.getName().matches(\"[^/]+/mmc-pack.json\"));\n}","typeGuard":null,"tryCatchPattern":"try { Modpack m = provider.readManifest(reader, zipPath, encoding); } catch (IOException e) { if (e.getMessage().equals(\"Not a valid MultiMC modpack\")) { /* try another provider */ } }","preventionTips":["Verify mmc-pack.json is at root or one folder deep before import","Use the matching provider for CurseForge/Modrinth packs","Avoid nesting zips inside zips"],"tags":["java","modpack","zip-layout","validation"],"backgroundTag":"file-not-found","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}