moeru-ai/airi · info · ActionError

PLACEMENT_FAILED

PLACEMENT_FAILED

Error message

${blockType} already at ${targetBlock.position}

What it means

Thrown by placeBlock (world-interactions.ts:70) with code PLACEMENT_FAILED when the block at targetDest already has the same name as the requested blockType. This is a no-op guard: the bot has the item and the target is loaded, but the placement would be redundant. Context payload is { blockType, position }.

Source

Thrown at integrations/minecraft/src/skills/actions/world-interactions.ts:70

      const Item = item.default(mineflayer.bot.version)
      await mineflayer.bot.creative.setInventorySlot(36, new Item(itemId, 1)) // 36 is first hotbar slot
    }
    block = mineflayer.bot.inventory.items().find(item => item.name.includes(blockType))
  }
  if (!block) {
    logger.log(`Don't have any ${blockType} to place.`)
    throw new ActionError('ITEM_NOT_FOUND', `Don't have any ${blockType} to place`, { item: blockType })
  }

  const targetBlock = mineflayer.bot.blockAt(targetDest)
  if (!targetBlock) {
    logger.log(`No block found at ${targetDest}.`)
    throw new ActionError('TARGET_NOT_FOUND', `No block found at ${targetDest}`, { position: targetDest })
  }

  if (targetBlock.name === blockType) {
    logger.log(`${blockType} already at ${targetBlock.position}.`)
    throw new ActionError('PLACEMENT_FAILED', `${blockType} already at ${targetBlock.position}`, { blockType, position: targetBlock.position })
  }

  const emptyBlocks = [
    'air',
    'water',
    'lava',
    'grass',
    'tall_grass',
    'snow',
    'dead_bush',
    'fern',
  ]
  if (!emptyBlocks.includes(targetBlock.name)) {
    logger.log(
      `${targetBlock.name} is in the way at ${targetBlock.position}.`,
    )
    await breakBlockAt(mineflayer, x, y, z)
    await sleep(200) // Wait for block to break

View on GitHub (pinned to 27111382b4)

Solutions

  1. Track already-placed positions in your build state and skip them before calling placeBlock.
  2. Treat this error as informational: catch PLACEMENT_FAILED and continue the build plan.
  3. Pre-check with bot.blockAt(targetDest).name === blockType and short-circuit.
  4. If the user expected a different result, verify blockType matches the registry id of what is actually there.

Example fix

// before
await placeBlock(bot, 'stone', x, y, z) // throws PLACEMENT_FAILED

// after
const existing = bot.bot.blockAt(new Vec3(x, y, z))
if (existing?.name !== 'stone') await placeBlock(bot, 'stone', x, y, z)
Defensive patterns

Strategy: validation

Validate before calling

const dest = new Vec3(Math.floor(x), Math.floor(y), Math.floor(z))
const existing = mineflayer.bot.blockAt(dest)
if (!existing || existing.name !== blockType) {
  await placeBlock(mineflayer, blockType, x, y, z, placeOn)
}

Type guard

const isAlreadyPlaced = (bot: Mineflayer, name: string, pos: Vec3): boolean =>
  bot.bot.blockAt(pos)?.name === name

Try / catch

try {
  await placeBlock(mineflayer, blockType, x, y, z, placeOn)
} catch (e) {
  if (e instanceof ActionError && e.code === 'PLACEMENT_FAILED' && e.message.includes('already')) {
    // treat as success, the block is there
  } else throw e
}

Prevention

When it happens

Trigger: Call placeBlock('oak_planks', ...) on a position that is already oak_planks, or re-run a build plan without tracking placed positions. The check is exact-name equality, so a 'stone' target will not match 'stone_bricks'.

Common situations: Idempotent build replays, schematic runner re-executing after a partial failure, AI planner re-issuing the same step, or a misunderstood target block.

Related errors


AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12). Data as JSON: /api/errors/86cfdc8b5977bc05. Report an issue: GitHub.