{"record":{"id":"21d17e12ae393f41","repo":"Anuken/Mindustry","slug":"too-many-long-strings-in-menuresult-reduce-your-a","errorCode":null,"errorMessage":"Too many long strings in MenuResult, reduce your amount of elements/IDs.","messagePattern":"Too many long strings in MenuResult, reduce your amount of elements/IDs\\.","errorType":"exception","errorClass":"ArcRuntimeException","httpStatus":null,"severity":"error","filePath":"core/src/mindustry/io/TypeIO.java","lineNumber":327,"sourceCode":"    public static MenuResult readMenuResult(Reads read){\n        MenuResult result = new MenuResult();\n\n        result.token = read.l();\n\n        //would be nice to count bytes but sadly that's not really viable here\n        int remainingChars = MenuResult.maxTotalStringLen;\n\n        byte exists = read.b();\n        if(exists != 0){\n            result.result = read.str(MenuResult.maxResultLen);\n            remainingChars -= result.result.length();\n        } //else, no result, remains null\n\n        int entries = read.us();\n        if(entries > MenuResult.maxTotalValues) throw new ArcRuntimeException(\"UI result entry count exceeds max entries: \" + entries);\n\n        for(int i = 0; i < entries; i++){\n            if(remainingChars <= 0) throw new ArcRuntimeException(\"Too many long strings in MenuResult, reduce your amount of elements/IDs.\");\n            String key = read.str(Math.min(remainingChars, MenuResult.maxValueLen));\n            remainingChars -= key.length();\n\n            byte type = read.b();\n\n            switch(type){\n                case 0 -> result.values.put(key, read.f());\n                case 1 ->  result.values.put(key, read.bool());\n                case 2 -> {\n                    if(remainingChars <= 0) throw new ArcRuntimeException(\"Too many long strings in MenuResult, reduce your amount of elements/IDs.\");\n                    String value = read.str(Math.min(remainingChars, MenuResult.maxValueLen));\n                    remainingChars -= value.length();\n                    result.values.put(key, value);\n                }\n                default -> throw new ArcRuntimeException(\"Unknown UI entry type: \" + type);\n            }\n        }\n        return result;","sourceCodeStart":309,"sourceCodeEnd":345,"githubUrl":"https://github.com/Anuken/Mindustry/blob/f695ad7e60323ebced984fa26d0bcf0bc54296b4/core/src/mindustry/io/TypeIO.java#L309-L345","documentation":"readMenuResult() enforces a global character budget (MenuResult.maxTotalStringLen = 6000) shared across all keys and string values. Before reading each key it checks remainingChars <= 0 and throws. This bounds total string memory per menu result.","triggerScenarios":"The cumulative length of menu-result keys (plus any prior strings) reaches or exceeds 6000 chars before a key is read.","commonSituations":"A menu with many or long element IDs/keys; a mod generating verbose keys; a malicious client.","solutions":["Shorten keys and reduce the number of entries so total chars stay under 6000.","Use compact key names in the UI builder."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Budget total key characters before sending a menu result.\nint total = 0;\nfor(var k : menuResult.values.keys()) total += k.length();\nif(total > MenuResult.maxTotalStringLen){\n    throw new IllegalStateException(\"Menu keys too long: \" + total);\n}","typeGuard":null,"tryCatchPattern":"try { MenuResult r = TypeIO.readMenuResult(read); }\ncatch(ArcRuntimeException e){ Log.err(\"Bad menu result\", e); con.kick(\"Invalid menu result.\"); }","preventionTips":["Keep total key+value characters under 6000 per menu.","Prefer short, compact key names."],"tags":["network","ui","menu","string-size","deserialization"],"backgroundTag":null,"analyzedSha":"f695ad7e60323ebced984fa26d0bcf0bc54296b4","analyzedAt":"2026-08-14T04:31:16.262Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}