{"record":{"id":"5c4250054fecaf39","repo":"Anuken/Mindustry","slug":"partprogress-object-need-a-type-string-field-ch","errorCode":null,"errorMessage":"PartProgress object need a 'type' string field. Check the PartProgress class for a list of constants.","messagePattern":"PartProgress object need a 'type' string field\\. Check the PartProgress class for a list of constants\\.","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/src/mindustry/mod/ContentParser.java","lineNumber":233,"sourceCode":"            data.remove(\"type\");\n            var result = make(bc);\n            readFields(result, data);\n            return result;\n        });\n        put(DrawPart.class, (type, data) -> {\n            Class<?> bc = resolve(data.getString(\"type\", \"\"), RegionPart.class);\n            data.remove(\"type\");\n            var result = make(bc);\n            readFields(result, data);\n            return result;\n        });\n        put(PartProgress.class, (type, data) -> {\n            //simple case: it's a string or number constant\n            if(data.isString()) return field(PartProgress.class, data.asString());\n            if(data.isNumber()) return PartProgress.constant(data.asFloat());\n\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){","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/Anuken/Mindustry/blob/f695ad7e60323ebced984fa26d0bcf0bc54296b4/core/src/mindustry/mod/ContentParser.java#L215-L251","documentation":"Thrown by the PartProgress parser when the value is an object lacking a `type` field. A PartProgress object must declare which named progress constant it extends before optional operations are applied.","triggerScenarios":"A mod JSON defines a PartProgress as an object with operations/fields but omits the required `type` key.","commonSituations":"Authoring weapon part progress curves and forgetting the base type, or copying an operation-only snippet.","solutions":["Add a `type` field referencing a constant on the PartProgress class (e.g. \"heat\", \"reload\").","Alternatively use the string shorthand (named constant) or number shorthand (constant(float))."],"exampleFix":"// before\n{ \"operations\": [ { \"op\": \"mul\", \"by\": 2 } ] }\n// after\n{ \"type\": \"heat\", \"operations\": [ { \"op\": \"mul\", \"by\": 2 } ] }","handlingStrategy":"validation","validationCode":"// Validate a PartProgress object has a 'type' before parsing.\nboolean validProgressObject(JsonValue v) {\n    return v.isString() || v.isNumber() || (v.isObject() && v.has(\"type\"));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include a `type` field on PartProgress objects.","Prefer the string/number shorthand for simple constants.","Keep the PartProgress constant list handy when authoring."],"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"}