moeru-ai/airi · warning · ActionError

ITEM_NOT_FOUND

ITEM_NOT_FOUND

Error message

Don't have any ${blockType} to place

What it means

Thrown by placeBlock (world-interactions.ts:59) with code ITEM_NOT_FOUND when neither the inventory nor the creative-setInventorySlot fallback produced an item whose name includes blockType. In creative mode the code first tries to inject the item via prismarine-item; in survival this branch is skipped entirely. Context payload is { item: blockType }.

Source

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

  const targetDest = new Vec3(Math.floor(x), Math.floor(y), Math.floor(z))

  let block = mineflayer.bot.inventory
    .items()
    .find(item => item.name.includes(blockType))
  if (!block && mineflayer.bot.game.gameMode === 'creative') {
    const mcData = McData.fromBot(mineflayer.bot)
    const itemId = mcData.getItemId(blockType)
    if (itemId) {
      const item = await import('prismarine-item')
      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',

View on GitHub (pinned to 27111382b4)

Solutions

  1. Verify the registry id spelling and case (e.g. 'oak_planks', not 'Oak Planks').
  2. In survival, ensure the block item is in inventory first (craft or takeFromChest).
  3. In creative, confirm McData.getItemId(blockType) returns a number; if null, the blockType is not in the loaded version.
  4. Pre-scan inventory with bot.inventory.items().map(i => i.name) and pass an id that appears.

Example fix

// before
await placeBlock(bot, 'Stone', x, y, z) // throws ITEM_NOT_FOUND (case)

// after
await takeFromChest(bot, 'stone', 64)
await placeBlock(bot, 'stone', x, y, z)
Defensive patterns

Strategy: validation

Validate before calling

let has = mineflayer.bot.inventory.items().some(i => i.name.includes(blockType))
if (!has && mineflayer.bot.game.gameMode !== 'creative') {
  await takeFromChest(mineflayer, blockType, 64)
  has = mineflayer.bot.inventory.items().some(i => i.name.includes(blockType))
}
if (has) await placeBlock(mineflayer, blockType, x, y, z, placeOn)

Type guard

const hasBlockItem = (bot: Mineflayer, name: string): boolean =>
  bot.bot.inventory.items().some(i => i.name.includes(name))

Try / catch

try {
  await placeBlock(mineflayer, blockType, x, y, z, placeOn)
} catch (e) {
  if (e instanceof ActionError && e.code === 'ITEM_NOT_FOUND') {
    // craft or takeFromChest the block item, then retry
  } else throw e
}

Prevention

When it happens

Trigger: Call placeBlock in survival with no matching block item in inventory, or in creative when McData.getItemId(blockType) returns null (unknown block id) and the inventory does not already contain it. The substring match is case-sensitive.

Common situations: blockType misspelled or wrong case, block id not present in the loaded minecraft-data version, item stored in a chest not inventory, or the bot is in survival but the caller assumed creative would supply it.

Related errors


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