{"record":{"id":"f0ec8509769ae209","repo":"Anuken/Mindustry","slug":"chained-partprogress-operations-must-be-an-array","errorCode":null,"errorMessage":"Chained PartProgress operations must be an array.","messagePattern":"Chained PartProgress operations must be an array\\.","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/src/mindustry/mod/ContentParser.java","lineNumber":249,"sourceCode":"\n            if(!data.has(\"type\")){\n                throw new RuntimeException(\"PartProgress object need a 'type' string field. Check the PartProgress class for a list of constants.\");\n            }\n\n            PartProgress base = (PartProgress)field(PartProgress.class, data.getString(\"type\"));\n\n            JsonValue opval =\n                data.has(\"operation\") ? data.get(\"operation\") :\n                data.has(\"op\") ? data.get(\"op\") : null;\n\n            //no singular operation, check for multi-operation\n            if(opval == null){\n                JsonValue opsVal =\n                    data.has(\"operations\") ? data.get(\"operations\") :\n                    data.has(\"ops\") ? data.get(\"ops\") : null;\n\n                if(opsVal != null){\n                    if(!opsVal.isArray()) throw new RuntimeException(\"Chained PartProgress operations must be an array.\");\n                    int i = 0;\n                    while(true){\n                        JsonValue val = opsVal.get(i);\n                        if(val == null) break;\n                        JsonValue op = val.has(\"operation\") ? val.get(\"operation\") :\n                            val.has(\"op\") ? val.get(\"op\") : null;\n\n                        base = parseProgressOp(base, op.asString(), val);\n                        i++;\n                    }\n                }\n\n                return base;\n            }\n\n            //this is the name of the method to call\n            String op = opval.asString();\n","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/Anuken/Mindustry/blob/f695ad7e60323ebced984fa26d0bcf0bc54296b4/core/src/mindustry/mod/ContentParser.java#L231-L267","documentation":"Thrown by the PartProgress parser when a `operations`/`ops` key is present but its value is not a JSON array. Chained operations must be a list of operation objects applied in sequence.","triggerScenarios":"A mod JSON writes `operations` (or `ops`) as a single object or scalar instead of an array of operation objects.","commonSituations":"Confusing the singular `operation`/`op` form (one op) with the plural `operations`/`ops` form (array).","solutions":["Wrap chained operations in a JSON array of operation objects.","If only one operation is needed, use the singular `operation` or `op` key instead."],"exampleFix":"// before\n{ \"type\": \"heat\", \"operations\": { \"op\": \"mul\", \"by\": 2 } }\n// after\n{ \"type\": \"heat\", \"operations\": [ { \"op\": \"mul\", \"by\": 2 } ] }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Guard: chained PartProgress operations must be a JSON array.\nboolean validOps(JsonValue v) {\n    return !v.has(\"operations\") && !v.has(\"ops\")\n        || (v.has(\"operations\") ? v.get(\"operations\").isArray() : v.get(\"ops\").isArray());\n}","tryCatchPattern":null,"preventionTips":["Use `operations`/`ops` only as arrays.","Use singular `operation`/`op` for a single operation.","Lint nested operation structures."],"tags":["modding","json","content-parser","part-progress"],"backgroundTag":null,"analyzedSha":"f695ad7e60323ebced984fa26d0bcf0bc54296b4","analyzedAt":"2026-08-14T04:31:16.262Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}