HMCL-dev/HMCL · error · IOException
"Missing MANIFEST.MF in file " + modFile
Error message
"Missing MANIFEST.MF in file " + modFile
What it means
Thrown by ForgeNewModMetadata.fromEmbeddedMod when the jar has no META-INF/MANIFEST.MF entry. The embedded-mod identification path builds metadata from the jar manifest attributes, so without a manifest it cannot proceed and gives up so fromFile can fall through to the toml path or fail outright.
Solutions
- Check that META-INF/MANIFEST.MF exists at the archive root of the jar.
- Re-download the mod — official builds always ship a manifest.
- If repackaging, use Gradle's jar task or preserve META-INF/MANIFEST.MF during repack.
- If the jar also lacks mods.toml, it is not a Forge 1.13+ mod; use the appropriate loader parser.
Example fix
// before
LocalModFile mod = ForgeNewModMetadata.fromFile(modManager, strippedJar, tree, type); // fails: no MANIFEST.MF
// after
if (tree.getEntry("META-INF/MANIFEST.MF") == null) {
throw new IllegalArgumentException(strippedJar + " lacks META-INF/MANIFEST.MF; re-download or repackage preserving the manifest");
}
LocalModFile mod = ForgeNewModMetadata.fromFile(modManager, strippedJar, tree, type); Defensive patterns
Strategy: validation
Validate before calling
if (tree.getEntry("META-INF/MANIFEST.MF") == null) {
throw new IllegalArgumentException(modFile + " has no jar manifest; cannot parse embedded mod metadata");
} Type guard
boolean hasManifest(ZipFileTree tree) { return tree.getEntry("META-INF/MANIFEST.MF") != null; } Try / catch
try {
LocalModFile mod = ForgeNewModMetadata.fromFile(modManager, modFile, tree, type);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("MANIFEST.MF")) {
// repack preserving META-INF/MANIFEST.MF or skip the jar
}
} Prevention
- Always preserve META-INF/MANIFEST.MF when repackaging jars
- Use standard build tools (Gradle jar task) that emit manifests
- Verify archive layout with unzip -l after any repack
When it happens
Trigger: fromFile -> fromEmbeddedMod on a jar where tree.getEntry("META-INF/MANIFEST.MF") returns null, and the embedded-mod identification cannot continue.
Common situations: A jar repackaged with a tool that dropped or relocated META-INF/MANIFEST.MF; jars built without a jar manifest; non-mod jars placed in the mods directory.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Bad Implementation-Title
- Bad Build-Number
- "File " + modFile + " is not a Forge 1.13+ or NeoForge mod."
- "Mod " + modFile + " ` ` is…
- "Invalid metadata file: " + jarInJarMetadata
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/4ab067e88fe3fa0e.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/addon/meta/ForgeNewModMetadata.java:256
} catch (IOException e) {
LOG.warning("Failed to parse MANIFEST.MF in file " + modFile);
}
}
ModLoaderType type = analyzeLoader(tomlParseResult, mod.getModId(), modLoaderType);
String logoPath = StringUtils.isNotBlank(mod.getLogoFile()) ? mod.getLogoFile() : metadata.getLogoFile();
return new LocalModFile(modManager, modManager.getLocalMod(mod.getModId(), type), modFile, mod.getDisplayName(), new LocalAddonFile.Description(mod.getDescription()),
mod.getAuthors(), jarVersion == null ? mod.getVersion() : mod.getVersion().replace("${file.jarVersion}", jarVersion), "",
mod.getDisplayURL(),
logoPath);
}
private static LocalModFile fromEmbeddedMod(ModManager modManager, Path modFile, ZipFileTree tree, ModLoaderType modLoaderType) throws IOException {
ZipArchiveEntry manifestFile = tree.getEntry("META-INF/MANIFEST.MF");
if (manifestFile == null)
throw new IOException("Missing MANIFEST.MF in file " + modFile);
Manifest manifest;
try (InputStream input = tree.getInputStream(manifestFile)) {
manifest = new Manifest(input);
}
List<ZipArchiveEntry> embeddedModFiles = List.of();
String embeddedDependenciesMod = manifest.getMainAttributes().getValue("Embedded-Dependencies-Mod");
if (embeddedDependenciesMod != null) {
ZipArchiveEntry embeddedModFile = tree.getEntry(embeddedDependenciesMod);
if (embeddedModFile == null) {
LOG.warning("Missing embedded-dependencies-mod: " + embeddedDependenciesMod);
throw new IOException();
}
embeddedModFiles = List.of(embeddedModFile);
} else {
ZipArchiveEntry jarInJarMetadata = tree.getEntry("META-INF/jarjar/metadata.json");View on GitHub (pinned to 24702dc5a0)