{"record":{"id":"e5fe52634054031e","repo":"Anuken/Mindustry","slug":"nested-arrays-are-not-allowed","errorCode":null,"errorMessage":"Nested arrays are not allowed","messagePattern":"Nested arrays are not allowed","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/src/mindustry/io/TypeIO.java","lineNumber":201,"sourceCode":"\n        byte type = read.b();\n        return switch(type){\n            case 0 -> null;\n            case 1 -> read.i();\n            case 2 -> read.l();\n            case 3 -> read.f();\n            case 4 -> {\n                byte exists = read.b();\n                if(exists != 0){\n                    //in a safe context, strings can only be 1200 chars\n                    yield read.str(safe ? 1200 : 0);\n                }else{\n                    yield null;\n                }\n            }\n            case 5 -> mapper == null ? content.getByID(ContentType.all[read.b()], read.s()) : mapper.get(ContentType.all[read.b()], read.s());\n            case 6 -> {\n                if(!allowArrays) throw new RuntimeException(\"Nested arrays are not allowed\");\n                short len = read.s();\n                if(len > maxArraySize) throw new RuntimeException(\"Invalid array size: \" + len);\n                IntSeq arr = new IntSeq(len);\n                for(int i = 0; i < len; i ++) arr.add(read.i());\n                yield arr;\n            }\n            case 7 -> new Point2(read.i(), read.i());\n            case 8 -> {\n                if(!allowArrays) throw new RuntimeException(\"Nested arrays are not allowed\");\n                int len = read.ub();\n                Point2[] out = new Point2[len];\n                for(int i = 0; i < len; i ++) out[i] = Point2.unpack(read.i());\n                yield out;\n            }\n            case 9 -> content.<UnlockableContent>getByID(ContentType.all[read.b()], read.s()).techNode;\n            case 10 -> read.bool();\n            case 11 -> read.d();\n            case 12 -> !box ? world.build(read.i()) : new BuildingBox(read.i());","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/Anuken/Mindustry/blob/f695ad7e60323ebced984fa26d0bcf0bc54296b4/core/src/mindustry/io/TypeIO.java#L183-L219","documentation":"TypeIO.readObject throws a plain RuntimeException when it encounters type tag 6 (IntSeq) and allowArrays is false. allowArrays is passed false by the recursive readObject call inside case 22 (Object[]), so an IntSeq nested inside an Object[] is rejected to prevent unbounded nested allocation. The guard is a structural check, not a data-integrity check.","triggerScenarios":"A serialized Object[] (tag 22) whose elements recurse via readObject(..., allowArrays=false); if any element is itself an array type (tag 6/8/14/16/18/22), this fires. Can also occur if a caller manually invokes readObject with allowArrays=false on a stream containing an array tag.","commonSituations":"A client sending a crafted or buggy packet that nests arrays inside an Object[] config; mod code reading configs in a restricted (safe) context.","solutions":["Do not nest array configs: ensure Object[] elements are scalar types (Integer, String, Content, etc.).","If array data is legitimate, send it as a top-level config (allowArrays=true path), not inside an Object[].","Validate on the write side that Object[] elements are non-array before calling writeObject."],"exampleFix":"// before\nObject[] nested = {new int[]{1,2,3}, \"x\"};\nTypeIO.writeObject(write, nested); // read-back throws 'Nested arrays are not allowed'\n\n// after\nObject[] flat = {1, 2, 3, \"x\"}; // scalars only\nTypeIO.writeObject(write, flat);","handlingStrategy":"validation","validationCode":"// Enforce no nested arrays in Object[] before writing\nstatic void assertFlat(Object[] objs) {\n    for (Object o : objs) if (o != null && o.getClass().isArray())\n        throw new IllegalArgumentException(\"Nested array in Object[] config: \" + o.getClass());\n}","typeGuard":"static boolean isFlatObjectArray(Object[] objs) {\n    if (objs == null) return true;\n    for (Object o : objs) if (o != null && o.getClass().isArray()) return false;\n    return true;\n}","tryCatchPattern":"try {\n    Object o = TypeIO.readObject(read);\n} catch (RuntimeException e) {\n    if (\"Nested arrays are not allowed\".equals(e.getMessage())) {\n        // reject the packet/config\n    }\n}","preventionTips":["Never put an array inside an Object[] config.","Send array data as top-level configs where allowArrays is true.","Validate flatness on the write side."],"tags":["network","deserialization","typeio","validation","nested-arrays"],"backgroundTag":null,"analyzedSha":"f695ad7e60323ebced984fa26d0bcf0bc54296b4","analyzedAt":"2026-08-14T04:31:16.262Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}