Anuken/Mindustry · warning · ValidateException

Player cannot control a building.

Error message

Player cannot control a building.

What it means

Thrown server-side as ValidateException when buildingControlSelect fails authorization: possession is not allowed by rules (state.rules.possessionAllowed is false AND player.bestCore() != build) OR netServer.admins.allowAction(buildSelect) denies it. Validates that a player may take direct control of a building (e.g. core units / turret possession).

Solutions

  1. On the server, handle ValidateException gracefully (it is an expected rejection).
  2. Clients should check state.rules.possessionAllowed and team match before requesting control.
  3. Review permission/admin configuration if legitimate control is blocked.

Example fix

// before
Call.buildingControlSelect(player, build);

// after
if(state.rules.possessionAllowed && player.team() == build.team()){
    Call.buildingControlSelect(player, build);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// client checks rules and team before requesting building control
if(!state.rules.possessionAllowed && player.bestCore() != build){
    return;
}
if(player.team() != build.team()){ return; }

Try / catch

try{ Call.buildingControlSelect(player, build); }catch(mindustry.net.ValidateException e){ Log.debug("rejected build control from @", e.player); }

Prevention

When it happens

Trigger: Client sends buildingControlSelect for a build when possession is disallowed by rules, or the admin layer denies the buildSelect action. Server-only throw (the @Remote called=Loc.server).

Common situations: Game mode/server disables possession (possessionAllowed=false) but a client still attempts it; permission plugin denies build control; client attempts to control an enemy-team building.

Related errors


AI-assisted analysis of Anuken/Mindustry@f695ad7e60 (2026-08-14). Data as JSON: /api/errors/970e3c25c82ae4ea. Report an issue: GitHub.

Appendix: source

Thrown at core/src/mindustry/input/InputHandler.java:747

        Events.fire(new ConfigEvent(build, player, value));
    }

    //only useful for servers or local mods, and is not replicated across clients
    //uses unreliable packets due to high frequency
    @Remote(targets = Loc.both, called = Loc.both, unreliable = true)
    public static void tileTap(@Nullable Player player, Tile tile){
        if(tile == null) return;

        Events.fire(new TapEvent(player, tile));
    }

    @Remote(targets = Loc.both, called = Loc.server)
    public static void buildingControlSelect(Player player, Building build){
        if(player == null || build == null || player.dead()) return;

        //make sure player is allowed to control the building
        if(net.server() && (!state.rules.possessionAllowed && player.bestCore() != build  || !netServer.admins.allowAction(player, ActionType.buildSelect, action -> action.tile = build.tile))){
            throw new ValidateException(player, "Player cannot control a building.");
        }

        if(player.team() == build.team && build.canControlSelect(player.unit())){
            var before = player.unit();

            Call.unitBuildingControlSelect(player.unit(), build);

            if(!before.dead && before.spawnedByCore && !before.isPlayer()){
                Call.unitDespawn(before);
            }
        }
    }

    @Remote(called = Loc.server)
    public static void unitBuildingControlSelect(Unit unit, Building build){
        if(unit == null || unit.dead()) return;

        //client skips checks to prevent ghost units

View on GitHub (pinned to f695ad7e60)