{"record":{"id":"22d4290ae41b8cc8","repo":"Anuken/Mindustry","slug":"player-cannot-configure-a-tile","errorCode":null,"errorMessage":"Player cannot configure a tile.","messagePattern":"Player cannot configure a tile\\.","errorType":"validation","errorClass":"ValidateException","httpStatus":null,"severity":"warning","filePath":"core/src/mindustry/input/InputHandler.java","lineNumber":722,"sourceCode":"\n    @Remote(targets = Loc.both, called = Loc.both, forward = true)\n    public static void tileConfig(@Nullable Player player, Building build, @Nullable Object value){\n        if(build == null && net.server()) throw new ValidateException(player, \"building is null\");\n        if(build == null) return;\n\n        if(net.server() && (!Units.canInteract(player, build) ||\n        !netServer.admins.allowAction(player, ActionType.configure, build.tile, action -> action.config = value))){\n\n            if(player.con != null){\n                var packet = new TileConfigCallPacket(); //undo the config on the client\n                packet.player = player;\n                packet.build = build;\n                packet.value = build.config();\n                player.con.send(packet, true);\n            }\n\n            if(!player.isLocal()){\n                throw new ValidateException(player, \"Player cannot configure a tile.\");\n            }else{\n                return;\n            }\n        }\n        if(player != null) build.updateLastAccess(player);\n        build.configured(player == null || player.dead() ? null : player.unit(), value);\n        Events.fire(new ConfigEvent(build, player, value));\n    }\n\n    //only useful for servers or local mods, and is not replicated across clients\n    //uses unreliable packets due to high frequency\n    @Remote(targets = Loc.both, called = Loc.both, unreliable = true)\n    public static void tileTap(@Nullable Player player, Tile tile){\n        if(tile == null) return;\n\n        Events.fire(new TapEvent(player, tile));\n    }\n","sourceCodeStart":704,"sourceCodeEnd":740,"githubUrl":"https://github.com/Anuken/Mindustry/blob/f695ad7e60323ebced984fa26d0bcf0bc54296b4/core/src/mindustry/input/InputHandler.java#L704-L740","documentation":"Thrown server-side as a ValidateException (RuntimeException) when a client's tile configure packet fails authorization: either Units.canInteract(player, build) is false, or netServer.admins.allowAction(configure) denies it. ValidateException carries the offending Player. It is not a bug; it is the anti-cheat/permission layer rejecting a packet. The server also sends a TileConfigCallPacket back to undo the client's local change.","triggerScenarios":"A client sends a configure action (building.config change) for a tile it cannot reach/interact with, or that the server's admin rules forbid (e.g. outside build range, wrong team, permission denied). Server-side check in InputHandler.tileConfig; only thrown when !player.isLocal().","commonSituations":"A malicious/buggy client tries to configure a building out of range or on an enemy team; permission plugins deny configure; desync where the client thinks it can reach a tile the server says it can't.","solutions":["On the server, treat ValidateException as expected: log/handle it, do not crash. The net layer already undoes the client config.","Ensure clients only send configure actions for buildings within Units.canInteract range and on their team.","Review permission/admin rules if legitimate actions are being denied.","If you write a custom server handler, catch ValidateException around remote invocations rather than letting it propagate."],"exampleFix":"// before: client fires configure unconditionally\nCall.tileConfig(player, build, value);\n\n// after: client checks reachability first\nif(Units.canInteract(player, build)){\n    Call.tileConfig(player, build, value);\n}","handlingStrategy":"try-catch","validationCode":"// client-side reachability check before sending configure\nif(net.client() && !Units.canInteract(player, build)){\n    return; // don't send a packet the server will reject\n}","typeGuard":null,"tryCatchPattern":"// server-side: ValidateException is expected for bad clients\ntry{ /* invoke remote configure */ }catch(mindustry.net.ValidateException e){ Log.debug(\"rejected configure from @\", e.player); }","preventionTips":["Clients should check Units.canInteract and team before sending configure.","Servers must treat ValidateException as expected, not a crash.","Audit permission/admin rules if valid actions are rejected.","Log rejected actions at debug level for diagnostics."],"tags":["network","validation","multiplayer","server","anti-cheat"],"backgroundTag":null,"analyzedSha":"f695ad7e60323ebced984fa26d0bcf0bc54296b4","analyzedAt":"2026-08-14T04:31:16.262Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}