Anuken/Mindustry · error · ModLoadException
Invalid file: No mod.json found.
Error message
Invalid file: No mod.json found.
What it means
loadMod resolves the mod root (zip or directory) and searches for a meta file (mod.json/plugin.hjson etc. via findMeta). If none is present it logs a warning and throws ModLoadException 'Invalid file: No mod.json found.' A mod cannot be loaded without a manifest.
Source
Thrown at core/src/mindustry/mod/Mods.java:1097
if(OS.isMac && (!(fi instanceof ZipFi))) fi.child(".DS_Store").delete();
Fi[] files = fi.list();
return files.length == 1 && files[0].isDirectory() ? files[0] : fi;
}
/** Loads a mod file+meta, but does not add it to the list.
* Note that directories can be loaded as mods. */
private LoadedMod loadMod(Fi sourceFile, boolean overwrite, boolean initialize) throws Exception{
ZipFi rootZip = null;
try{
Fi zip = resolveRoot(sourceFile.isDirectory() ? sourceFile : (rootZip = new ZipFi(sourceFile)));
ModMeta meta = findMeta(zip);
if(meta == null){
Log.warn("Mod @ doesn't have a '[mod/plugin].[h]json' file, skipping.", zip);
throw new ModLoadException("Invalid file: No mod.json found.");
}
String camelized = meta.name.replace(" ", "");
String mainClass = meta.main == null ? camelized.toLowerCase(Locale.ROOT) + "." + camelized + "Mod" : meta.main;
String baseName = meta.name.toLowerCase(Locale.ROOT).replace(" ", "-");
var other = mods.find(m -> m.name.equals(baseName));
if(other != null){
//steam mods can't really be deleted, they need to be unsubscribed
if(overwrite && !other.hasSteamID()){
//close the classloader for jar mods
if(!android){
ClassLoaderCloser.close(other.loader);
}else if(other.loader != null){
//Try to remove cache for Android 14 security problem
Fi cacheDir = new Fi(Core.files.getCachePath()).child("mods");View on GitHub (pinned to f695ad7e60)
Solutions
- Ensure mod.json (or plugin.json/plugin.hjson/mod.hjson) exists at the root of the zip/directory.
- Re-zip so the manifest is at the archive's top level, not inside a subfolder.
- Use the exact expected manifest filename.
Example fix
// before: mymod.zip // mymod/ // mod.json // (nested -> not found) // after: mymod.zip // mod.json // ...files...
Defensive patterns
Strategy: validation
Validate before calling
// Verify a manifest exists at the archive/directory root before importing.
Fi root = resolveRoot(source);
boolean hasMeta = false;
for(String name : new String[]{"mod.json","mod.hjson","plugin.json","plugin.hjson"}) {
if(root.child(name).exists()){ hasMeta = true; break; }
}
if(!hasMeta) throw new ModLoadException("Invalid file: No mod.json found."); Type guard
boolean hasManifest(Fi root){
return java.util.List.of("mod.json","mod.hjson","plugin.json","plugin.hjson").stream().anyMatch(n -> root.child(n).exists());
} Try / catch
try {
mods.loadMod(file);
} catch(ModLoadException e) {
if(e.getMessage().contains("No mod.json")) { /* fix archive layout */ }
else throw e;
} Prevention
- Place mod.json at the zip root, not in a subfolder.
- Use the exact expected manifest filename.
- Verify archive layout before publishing (unzip -l).
When it happens
Trigger: The supplied source file/directory contains no recognized manifest at its root.
Common situations: Zipped the parent folder instead of its contents (manifest ends up nested one level deep); wrong filename; manifest named meta.json instead of mod.json; plain data archive loaded as a mod.
Related errors
- A mod with the name '{baseName}' is already imported.
- This mod/plugin has loaded Mindustry dependencies from its o
- Two content objects defined with the same name: '{content.na
- Attribute definitions must be objects, e.g. {heat: 10}
- Unknown status effect: '
AI-assisted analysis of Anuken/Mindustry@f695ad7e60 (2026-08-14).
Data as JSON: /api/errors/0cf556b052f7a86f.
Report an issue: GitHub.