Anuken/Mindustry · error · SerializationException

Patch must be a JSON object.

Error message

Patch must be a JSON object.

What it means

DataPatcher parses each patch asset's JSON; if the parsed root value is not a JsonValue object (e.g. the patch is an array, scalar, or parsed to a non-JsonValue type), it throws SerializationException 'Patch must be a JSON object.' Patches are applied as object key/value merges.

Source

Thrown at core/src/mindustry/mod/DataPatcher.java:231

                        if(cont.minfo.asset != null) cont.minfo.asset.errored = true;
                        parser.markError(cont, dpMod, cont.minfo.sourceFile, t);
                    }
                }
            }

            if(reloadContentWorld) fixContentArrays();
        }

        var patchIt = patches.iterator();
        while(patchIt.hasNext()){
            PatchAsset set = patchIt.next();

            set.warnings.clear();
            set.error = false;

            try{
                Object someValue = parser.getJson().fromJson(null, Jval.read(set.patch).toString(Jformat.plain));
                if(!(someValue instanceof JsonValue value)) throw new SerializationException("Patch must be a JSON object.");

                if(Vars.state.rules.planet != null && value.has("requiredPlanets")){
                    JsonValue req = value.get("requiredPlanets");
                    value.remove("requiredPlanets");

                    //this should be ignored unless this instance is a dedicated server
                    if(Vars.headless){
                        String[] planets = req.isArray() ? req.asStringArray() : new String[]{req.asString()};
                        if(!Structs.contains(planets, Vars.state.rules.planet.name)){
                            patchIt.remove();
                            continue;
                        }
                    }
                }

                set.json = value;
                currentlyApplyingPatch = set;
                visitStack.clear();

View on GitHub (pinned to f695ad7e60)

Solutions

  1. Make the patch file a JSON object at the top level.
  2. Validate it parses to an object before submission.
  3. Remove array-style patch-op wrappers if present.

Example fix

// before (patch.json)
[ { "op": "replace", "path": "a", "value": 1 } ]

// after
{ "a": 1 }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure a patch is a JSON object before applying.
Object parsed = parser.getJson().fromJson(null, Jval.read(patch).toString(Jformat.plain));
if(!(parsed instanceof JsonValue v) || !v.isObject()) {
    throw new SerializationException("Patch must be a JSON object.");
}

Type guard

boolean isJsonObjectPatch(String json){
    try {
        Object p = parser.getJson().fromJson(null, Jval.read(json).toString(Jformat.plain));
        return p instanceof JsonValue v && v.isObject();
    } catch(Exception e){ return false; }
}

Try / catch

try {
    DataPatcher.apply(patch);
} catch(SerializationException e) {
    if(e.getMessage().equals("Patch must be a JSON object.")) { /* rewrite patch root as object */ }
    else throw e;
}

Prevention

When it happens

Trigger: A patch file's top-level JSON is not an object — it is an array, a bare string/number, or malformed such that fromJson does not yield a JsonValue.

Common situations: Hand-edited patch with wrong top-level shape; patch generated by tooling emitting an array of ops; syntax error causing unexpected parse result.

Related errors


AI-assisted analysis of Anuken/Mindustry@f695ad7e60 (2026-08-14). Data as JSON: /api/errors/05baf39d378dbd2e. Report an issue: GitHub.