Wiki 9Minecraft Wiki 9Minecraft

Execute at Block Variant

Run commands conditionally based on specific block states and custom properties using the modern execute syntax.

6Sections
3Code examples
4Known errors

In Minecraft Bedrock add-on development, you frequently need to trigger mechanics only when an entity is standing on, looking at, or near a very specific variant of a block. Since the flattened block update and the introduction of the new execute syntax, checking for block variants requires using block state arrays rather than legacy data values. You reach for this pattern when building floor-pad puzzles, directional conveyor belts, or custom crop growth systems inside behavior pack functions.

Understanding Block States in Commands

Historically, Bedrock Edition relied on numeric data values (also known as metadata or aux values) to distinguish between variants of the same base block. For example, different colors of wool or orientations of stairs were represented by a single integer following the block identifier. In modern Bedrock versions, numeric data values are completely rejected if your behavior pack manifest specifies a `min_engine_version` of 1.19.80 or higher, or if you use the updated `/execute` syntax introduced in 1.19.50.

Instead of integers, commands now require an explicit block state array enclosed in square brackets immediately following the block identifier, such as `minecraft:oak_log["pillar_axis"="y"]`. A single block can have multiple states defined at once, separated by commas. When testing for a block using `/execute if block`, you do not need to list every single state that the block possesses in the world. You only need to specify the exact states you care about for your condition to pass.

If you omit the square brackets entirely—or leave them empty like `minecraft:stone[]`—the command will match any variant of that block, regardless of its current states. This partial matching behavior is immensely useful for add-on creators. For instance, you can check if a player is standing on a lit furnace without caring which cardinal direction the furnace is facing, or check the facing direction of a custom block without caring whether its custom boolean toggle state is currently true or false.

State Value TypeSyntax RequirementValid Example
StringBoth the state name and the value must be enclosed in double quotes, separated by an equals sign.["minecraft:cardinal_direction"="north"]
IntegerThe state name is in double quotes, while the numeric value is written as a plain unquoted integer.["age"=3]
BooleanThe state name is in double quotes, and the value is written as unquoted true or false.["open_bit"=true]

Core Syntax for Executing at a Block Variant

Because blocks are static grid elements and not entities, you cannot pass a block directly into an `@e` target selector. To "execute at a block", you must anchor the execution context to an entity (like a player, an armor stand marker, or a projectile) and offset the execution position using `at` or `positioned`, followed by the `if block` or `unless block` subcommand. The general flow is to shift the command's origin to the target entity, evaluate the block at a relative coordinate offset, and then run your payload command.

When chaining these subcommands in an `.mcfunction` file, pay close attention to where the execution position is located when the final command runs. Using `execute as @a at @s if block ~ ~-1 ~ ...` checks the block directly beneath the player's feet, but the execution position remains at the player's feet (`~ ~ ~`). If you want the resulting particle or structure load to happen centered on the block itself, or if you are probing a block several meters away, you should step the position forward using `positioned` before running the `if block` check.

Below is a practical function file showing several ways to detect vanilla block variants relative to players. This includes checking string states for colors, boolean states for redstone components, and combining multiple states into a single check.

BP/functions/check_vanilla_variants.mcfunction
# 1. Give speed to any player standing on Magenta Glazed Terracotta facing North
execute as @a at @s if block ~ ~-1 ~ minecraft:magenta_glazed_terracotta["facing_direction"=2] run effect @s speed 2 1 true

# 2. Check for a specific stone slab variant (bottom half, stone brick type) at the player's feet
execute as @a at @s if block ~ ~ ~ minecraft:stone_block_slab["stone_slab_type"="stone_brick","top_slot_bit"=false] run title @s actionbar Stepping on a lower stone brick slab

# 3. Shift the execution position to 2 blocks in front of the player's eyes, then check for a powered lever
execute as @a at @s anchored eyes positioned ^ ^ ^2 if block ~ ~ ~ minecraft:lever["open_bit"=true] run particle minecraft:villager_happy ~ ~ ~

# 4. Detect a fully grown wheat crop and replace it, keeping execution centered on the crop
execute as @a at @s positioned ~ ~ ~ if block ~ ~ ~ minecraft:wheat["growth"=7] run setblock ~ ~ ~ minecraft:wheat["growth"=0] destroy

Defining and Detecting Custom Block Variants

The `if block` state filter becomes even more powerful when paired with custom blocks defined in your behavior pack. When you create a custom block, you can declare custom states inside the `description.states` object (or using built-in vanilla transformation traits like `minecraft:placement_direction`). Every custom state you define must have a namespace prefix, just like your block identifier. Once registered in the block JSON, these states are immediately accessible to the `/execute` command parser.

Suppose you are building a custom puzzle pad block (`wiki:glyph_pad`) that has an integer state for its elemental charge (`wiki:charge`) and uses the placement direction trait to track which way the player placed it. First, you define the block in your behavior pack so the game engine recognizes the block identifier and its valid state combinations.

BP/blocks/glyph_pad.json
{
  "format_version": "1.20.80",
  "minecraft:block": {
    "description": {
      "identifier": "wiki:glyph_pad",
      "traits": {
        "minecraft:placement_direction": {
          "enabled_states": [
            "minecraft:cardinal_direction"
          ]
        }
      },
      "states": {
        "wiki:charge": [0, 1, 2, 3],
        "wiki:is_locked": [false, true]
      }
    },
    "components": {
      "minecraft:destructible_by_mining": {
        "seconds_to_destroy": 1.5
      },
      "minecraft:geometry": "minecraft:geometry.full_block"
    },
    "permutations": [
      {
        "condition": "q.block_state('wiki:charge') == 3",
        "components": {
          "minecraft:light_emission": 15
        }
      }
    ]
  }
}

Executing Commands on Custom Block States

With `wiki:glyph_pad` registered in your behavior pack, you can now write function recipes that react to its exact permutation in the world. Notice that in the block JSON above, we enabled the `minecraft:cardinal_direction` state via traits, and we created two custom states: `wiki:charge` (an integer from 0 to 3) and `wiki:is_locked` (a boolean). When referencing these in an `.mcfunction` file, you must wrap the full namespaced state key in quotes, such as `"wiki:charge"=3`.

A common pattern in add-ons is using a repeating function (driven by `tick.json`) or an entity animation controller to poll the blocks around players and advance the block's state using `/setblock` or `/fill`. The function below demonstrates how to read specific combinations of our custom states and push the player in the direction the pad is facing, or increment the charge state.

BP/functions/glyph_pad_logic.mcfunction
# Only trigger if the pad under the player is unlocked and at maximum charge (3)
execute as @a at @s if block ~ ~-1 ~ wiki:glyph_pad["wiki:is_locked"=false,"wiki:charge"=3] run tag @s add on_charged_pad

# Apply directional movement based on the cardinal direction trait of the charged pad
execute as @a[tag=on_charged_pad] at @s if block ~ ~-1 ~ wiki:glyph_pad["minecraft:cardinal_direction"="north"] run tp @s ~ ~ ~-0.5
execute as @a[tag=on_charged_pad] at @s if block ~ ~-1 ~ wiki:glyph_pad["minecraft:cardinal_direction"="south"] run tp @s ~ ~ ~0.5
execute as @a[tag=on_charged_pad] at @s if block ~ ~-1 ~ wiki:glyph_pad["minecraft:cardinal_direction"="east"] run tp @s ~0.5 ~ ~
execute as @a[tag=on_charged_pad] at @s if block ~ ~-1 ~ wiki:glyph_pad["minecraft:cardinal_direction"="west"] run tp @s ~-0.5 ~ ~

# Discharge the pad back to 0 and lock it after a player steps on a North-facing max-charge pad
execute as @a[tag=on_charged_pad] at @s if block ~ ~-1 ~ wiki:glyph_pad["minecraft:cardinal_direction"="north","wiki:charge"=3] run setblock ~ ~-1 ~ wiki:glyph_pad["minecraft:cardinal_direction"="north","wiki:charge"=0,"wiki:is_locked"=true]

# Clean up the temporary processing tag
tag @a[tag=on_charged_pad] remove on_charged_pad

Scanning a Volume Using Marker Entities

Because `/execute if block` only evaluates a single coordinate at a time, beginners often ask how to execute a command at every instance of a block variant within a room or arena. While the Script API (`@minecraft/server`) or custom block tick components are better suited for large-scale block scanning, you can solve this purely with command recipes by using invisible marker entities (such as an `armor_stand` or a custom dummy entity) placed at the block locations, or by sweeping a marker across a grid.

Another pure-command trick for checking if a player is near a block variant—without requiring them to stand directly on top of it—is to chain multiple `positioned` offsets or use `execute if blocks` to compare against a template. However, if you place a lightweight custom marker entity inside your special blocks when they are constructed, you can execute `as @e[type=wiki:block_marker] at @s if block ~ ~ ~ wiki:glyph_pad["wiki:charge"=3]` to run commands directly from the block's exact coordinates anywhere in a ticking area, with almost zero performance overhead.

When modifying a block's state via `setblock` after an `if block` check (as shown in the previous section), remember that `/setblock` overwrites all states of the block at that coordinate with their default values unless you explicitly specify them in the `setblock` state array. If your block is facing south, and you run `setblock ~ ~-1 ~ wiki:glyph_pad["wiki:charge"=0]`, its cardinal direction will reset to the default (north). This is why the recipe above checks the cardinal direction first and includes that exact same direction in the resulting `setblock` command.

Vanilla Block Flattening Considerations

Over several updates starting around 1.19.70 and continuing through 1.20.x and 1.21.x, Bedrock Edition has undergone a continuous process known as "flattening." Blocks that used to be grouped under a single identifier with a type state—such as `minecraft:wool["color"="red"]`, `minecraft:log["old_log_type"="oak"]`, or `minecraft:wooden_slab`—have been split into distinct, standalone block identifiers like `minecraft:red_wool`, `minecraft:oak_log`, and `minecraft:oak_slab`.

Before writing an `execute if block` recipe for a vanilla block variant, verify whether the variant is currently a distinct block ID or a block state. Type variations (wood species, wool/concrete/terracotta colors, coral types, stone variants) are now almost entirely separate block identifiers. Functional or orientation variations (growth stages, liquid depth, facing direction, top/bottom slab placement, open/closed doors, lit/unlit redstone components) remain as block states inside square brackets.

If you write a function in a behavior pack whose `manifest.json` has an older `min_engine_version`, legacy unflattened block names might still work in that specific pack, but it is strongly recommended to update your `min_engine_version` to match current stable releases and use the flattened block identifiers alongside explicit directional or functional states.

Which versions this applies to

Applies to Minecraft Bedrock 1.19.50 and newer (when the new execute syntax was introduced). Mandatory for behavior packs with a min_engine_version of 1.19.80 or higher, where numeric block data values were completely removed in favor of bracketed block states. Custom block traits like placement_direction require format_version 1.20.20 or higher. No experimental toggles are required.

When it does not work

What you seeWhyThe fix
Function fails to parse on world load with Content Log error: "Syntax error: Unexpected '0': at ..."You placed an integer data value after the block identifier (for example, `if block ~ ~-1 ~ minecraft:wool 0`) in a behavior pack using the modern execute syntax or a `min_engine_version` of 1.19.80+.Replace the numeric data value with a flattened block ID and/or a bracketed block state array, such as `minecraft:white_wool` or `minecraft:oak_log["pillar_axis"="y"]`.
Command error: "Block state 'facing_direction' is not valid on block..." or "Invalid block state"Not all directional blocks use the same vanilla state name. Some blocks use the integer state `"facing_direction"` (0 to 5), others use `"minecraft:cardinal_direction"` (north, south, east, west), and logs/pillars use `"pillar_axis"` (x, y, z).Test the block in-game using the chat command `/execute if block ~ ~-1 ~ <block_name>[` and look at the auto-complete suggestions to see the exact state name and value type registered to that specific block.
Syntax error: Unexpected "north": at ... ["minecraft:cardinal_direction"=>>north<<]String state values and all state names in Bedrock commands must be wrapped in double quotes. Leaving a string value unquoted causes the command parser to reject the line.Wrap both the state key and the string value in double quotes: `["minecraft:cardinal_direction"="north"]`. Do not quote boolean (`true`/`false`) or integer (`0`, `1`, `2`) values.
Custom block state check always fails or throws an unknown state error in `.mcfunction` files.You omitted the namespace on your custom state inside the square brackets (writing `["charge"=3]` instead of `["wiki:charge"=3]`), or the value you are testing for is not listed in the `description.states` array of your block's JSON file.Always include the full namespace inside the quotes for custom block states (`"namespace:state_name"=value`), and confirm the behavior pack loaded without JSON errors in the Content Log.

Reference, straight from the game files

Read out of the game itself, so the ids match the version you are building for.