HMCL-dev/HMCL · error · IOException
File is not a Fabric mod.
Error message
File ${modFile} is not a Fabric mod. What it means
Thrown by FabricModMetadata.fromFile when a jar passed to the mod manager has no fabric.mod.json entry. HMCL identifies Fabric mods by parsing fabric.mod.json at the jar root; without it the file cannot be recognized as a Fabric mod and metadata cannot be extracted. This is a guard against calling the parser on an unsupported or corrupt jar.
Solutions
- Verify the jar actually contains fabric.mod.json at its root (e.g. unzip -l mod.jar | grep fabric.mod.json); if not, it is not a Fabric mod.
- Re-download the mod from its official source; the jar is likely corrupt, wrong-loader, or repackaged incorrectly.
- If it is a Forge/NeoForge mod, use ForgeOldModMetadata/ForgeNewModMetadata.fromFile instead of the Fabric parser.
- If repackaging, ensure fabric.mod.json sits at the archive root, not in a nested folder.
Example fix
// before
LocalModFile mod = FabricModMetadata.fromFile(modManager, modFile, tree);
// after
if (tree.getEntry("fabric.mod.json") == null) {
throw new IllegalArgumentException(modFile + " has no fabric.mod.json; not a Fabric mod");
}
LocalModFile mod = FabricModMetadata.fromFile(modManager, modFile, tree); Defensive patterns
Strategy: validation
Validate before calling
if (tree.getEntry("fabric.mod.json") == null) {
// not a Fabric mod; route to another loader parser or skip
return null;
} Type guard
boolean isFabricMod(ZipFileTree tree) { return tree.getEntry("fabric.mod.json") != null; } Try / catch
try {
LocalModFile mod = FabricModMetadata.fromFile(modManager, modFile, tree);
} catch (IOException e) {
LOG.warning("Skipping non-Fabric jar: " + modFile);
} Prevention
- Check for fabric.mod.json before invoking the Fabric parser
- Route jars to the parser matching their loader (check fabric.mod.json / mods.toml / mcmod.info in order)
- Re-download mods from official sources instead of repackaging
When it happens
Trigger: Calling FabricModMetadata.fromFile(modManager, modFile, tree) on a jar whose ZipFileTree has no entry named 'fabric.mod.json'.
Common situations: Pointing the mod scanner at a Forge/Quilt-lite or plain library jar; a manually repackaged mod where fabric.mod.json was moved to a subdirectory or deleted; scanning non-mod jars in the mods folder.
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
- "File " + modFile + " is not a Forge mod."
- "File " + modFile + " is not a Forge 1.13+ or NeoForge mod."
- Theme pack directory does not contain
- Theme pack does not contain
- Missing release file
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/23fe7559516be5ed.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/addon/meta/FabricModMetadata.java:66
public FabricModMetadata() {
this("", "", "", "", "", Collections.emptyList(), Collections.emptyMap());
}
public FabricModMetadata(String id, String name, String version, String icon, String description, List<FabricModAuthor> authors, Map<String, String> contact) {
this.id = id;
this.name = name;
this.version = version;
this.icon = icon;
this.description = description;
this.authors = authors;
this.contact = contact;
}
public static LocalModFile fromFile(ModManager modManager, Path modFile, ZipFileTree tree) throws IOException, JsonParseException {
ZipArchiveEntry mcmod = tree.getEntry("fabric.mod.json");
if (mcmod == null)
throw new IOException("File " + modFile + " is not a Fabric mod.");
FabricModMetadata metadata = JsonUtils.fromNonNullJsonFully(tree.getInputStream(mcmod), FabricModMetadata.class);
String authors = metadata.authors == null ? "" : metadata.authors.stream().map(author -> author.name).collect(Collectors.joining(", "));
return new LocalModFile(modManager, modManager.getLocalMod(metadata.id, ModLoaderType.FABRIC), modFile, metadata.name, new LocalAddonFile.Description(metadata.description),
authors, metadata.version, "", metadata.contact != null ? metadata.contact.getOrDefault("homepage", "") : "", metadata.icon);
}
@JsonAdapter(FabricModAuthorSerializer.class)
public static final class FabricModAuthor {
private final String name;
public FabricModAuthor() {
this("");
}
public FabricModAuthor(String name) {
this.name = name;
}
}View on GitHub (pinned to 24702dc5a0)