{"record":{"id":"9ebbce3ecb9ca004","repo":"Anuken/Mindustry","slug":"invalid-block-id-in-block-plans-client-is-likely","errorCode":null,"errorMessage":"Invalid block ID in block plans! Client is likely using an incorrectly configured mod.","messagePattern":"Invalid block ID in block plans! Client is likely using an incorrectly configured mod\\.","errorType":"exception","errorClass":"ArcRuntimeException","httpStatus":null,"severity":"error","filePath":"core/src/mindustry/io/TypeIO.java","lineNumber":710,"sourceCode":"                write.b((byte)plan.rotation);\n            }\n            writeObject(write, validClientPlanConfig(plan.config) ? plan.config : null);\n        }\n    }\n\n    public static ClientBuildPlans readClientPlans(Reads read){\n        short amount = read.s();\n\n        if(amount == 0) return null;\n        if(amount > maxPlayerPreviewPlans) throw new RuntimeException(\"Too many plans: \" + amount);\n\n        var result = new ClientBuildPlans();\n        result.ensureCapacity(Math.min(amount, maxPlayerPreviewPlans));\n        for(int i = 0; i < amount; i++){\n            int x = read.us();\n            int y = read.us();\n            Block block = Vars.content.block(read.us());\n            if(block == null) throw new ArcRuntimeException(\"Invalid block ID in block plans! Client is likely using an incorrectly configured mod.\");\n            int rotation = (block.rotate ? read.b() : 0);\n            Object config = readClientPlanConfig(read);\n            BuildPlan plan = new BuildPlan(x, y, rotation, block, config);\n            result.add(plan);\n        }\n\n        return result;\n    }\n\n    static @Nullable Object readClientPlanConfig(Reads read){\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 5 -> content.getByID(ContentType.all[read.b()], read.s());\n            case 10 -> read.bool();","sourceCodeStart":692,"sourceCodeEnd":728,"githubUrl":"https://github.com/Anuken/Mindustry/blob/f695ad7e60323ebced984fa26d0bcf0bc54296b4/core/src/mindustry/io/TypeIO.java#L692-L728","documentation":"readClientPlans() resolves each plan's block via Vars.content.block(id). If the ID maps to no registered Block (null), it throws ArcRuntimeException with a message pointing at an incorrectly configured mod. The content registries must agree between sender and receiver.","triggerScenarios":"A client plan references a block ID that the server's content registry does not contain.","commonSituations":"Client has a mod the server lacks (or vice versa); mod load order differs; block content IDs shifted after a mod update; an out-of-range ID.","solutions":["Ensure server and client load exactly the same mods in the same order.","Update mods to matching versions on both sides.","Server: catch ArcRuntimeException and kick with a mod-mismatch message."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Resolve the block id locally before serializing/sending.\nBlock b = Vars.content.block(id);\nif(b == null){\n    throw new IllegalStateException(\"Unknown block id \" + id + \" — mod/content mismatch\");\n}","typeGuard":null,"tryCatchPattern":"try { ClientBuildPlans p = TypeIO.readClientPlans(read); }\ncatch(ArcRuntimeException e){ Log.err(\"Block mismatch in client plans\", e); con.kick(\"Mod mismatch.\"); }","preventionTips":["Keep server and client mod lists identical and in the same load order.","Register content deterministically so block IDs stay stable across peers."],"tags":["network","build-plan","mod","content-mismatch"],"backgroundTag":null,"analyzedSha":"f695ad7e60323ebced984fa26d0bcf0bc54296b4","analyzedAt":"2026-08-14T04:31:16.262Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}