{"record":{"id":"8b42ccad5caa836f","repo":"moeru-ai/airi","slug":"item-not-found","errorCode":"ITEM_NOT_FOUND","errorMessage":"You do not have any ${itemName} to equip","messagePattern":"You do not have any (.+?) to equip","errorType":"exception","errorClass":"ActionError","httpStatus":null,"severity":"warning","filePath":"integrations/minecraft/src/skills/actions/inventory.ts","lineNumber":24,"sourceCode":"import { useLogger } from '../../utils/logger'\nimport { goToPlayer, goToPosition } from '../movement'\nimport { getNearestBlock } from '../world'\n\nconst logger = useLogger()\n\n/**\n * Equip an item from the bot's inventory.\n * @param mineflayer The mineflayer instance.\n * @param itemName The name of the item to equip.\n * @throws {ActionError} When the item is not in inventory.\n */\nexport async function equip(mineflayer: Mineflayer, itemName: string): Promise<void> {\n  const item = mineflayer.bot.inventory\n    .items()\n    .find(item => item.name.includes(itemName))\n  if (!item) {\n    logger.log(`You do not have any ${itemName} to equip.`)\n    throw new ActionError('ITEM_NOT_FOUND', `You do not have any ${itemName} to equip`, { item: itemName })\n  }\n  let destination: 'hand' | 'head' | 'torso' | 'legs' | 'feet' = 'hand'\n  if (itemName.includes('leggings'))\n    destination = 'legs'\n  else if (itemName.includes('boots'))\n    destination = 'feet'\n  else if (itemName.includes('helmet'))\n    destination = 'head'\n  else if (itemName.includes('chestplate'))\n    destination = 'torso'\n\n  await mineflayer.bot.equip(item, destination)\n  logger.log(`Equipped ${itemName}.`)\n}\n\n/**\n * Discard an item from the bot's inventory.\n * @param mineflayer The mineflayer instance.","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/integrations/minecraft/src/skills/actions/inventory.ts#L6-L42","documentation":"Thrown by equip() when no inventory item's name includes the supplied itemName substring. The lookup uses Array.find with item.name.includes(itemName), so any substring match would have satisfied it; reaching the throw means zero items in inventory contain that substring.","triggerScenarios":"Calling equip(mineflayer, 'sword') when the bot has no sword in inventory. Calling equip with a misspelled or partial name that does not appear in any item.name. Inventory desync where the server has not yet sent the slot update after a craft/pickup.","commonSituations":"Caller assumed a tool existed without first running ensure* helpers. itemName typo (e.g. 'pick axe' instead of 'pickaxe'). Item is in the chest or on the ground but not in inventory. Race condition: equip called immediately after craft before the slot event propagated.","solutions":["Pre-check with getItemCount(mineflayer, itemName) > 0 before calling equip.","Run the appropriate ensure* helper (ensurePickaxe, ensureSword, etc.) before equip.","Add a short sleep (e.g. 200ms) between a craft and equip to allow the inventory slot event to propagate.","Use exact item names from mineflayer.bot.registry.itemsByName to avoid substring mismatches."],"exampleFix":"// before\nexport async function equip(mineflayer: Mineflayer, itemName: string): Promise<void> {\n  const item = mineflayer.bot.inventory.items().find(item => item.name.includes(itemName))\n  if (!item) {\n    throw new ActionError('ITEM_NOT_FOUND', `You do not have any ${itemName} to equip`, { item: itemName })\n  }\n  // ...\n}\n\n// after — list candidate names so the caller can correct the input\nif (!item) {\n  const names = mineflayer.bot.inventory.items().map(i => i.name)\n  throw new ActionError('ITEM_NOT_FOUND', `You do not have any ${itemName} to equip`, {\n    item: itemName,\n    inventory: names,\n  })\n}","handlingStrategy":"validation","validationCode":"import { getItemCount } from './inventory'\n\nfunction hasItem(mineflayer: Mineflayer, itemName: string): boolean {\n  return getItemCount(mineflayer, itemName) > 0\n}\n\n// Pre-check before equipping\nif (!hasItem(mineflayer, itemName)) {\n  await ensurePickaxe(mineflayer) // or whichever ensure helper fits\n}\nawait equip(mineflayer, itemName)","typeGuard":"function findInventoryItem(mineflayer: Mineflayer, itemName: string) {\n  return mineflayer.bot.inventory.items().find(i => i.name.includes(itemName))\n}\n\n// Use as a guard before equip\nconst item = findInventoryItem(mineflayer, 'sword')\nif (item) {\n  await equip(mineflayer, 'sword')\n}","tryCatchPattern":"import { ActionError } from '../../utils/errors'\n\ntry {\n  await equip(mineflayer, itemName)\n} catch (err) {\n  if (err instanceof ActionError && err.code === 'ITEM_NOT_FOUND') {\n    // Try to ensure the item via the appropriate helper, then equip once\n    if (itemName.includes('pickaxe')) await ensurePickaxe(mineflayer)\n    else if (itemName.includes('sword')) await ensureSword(mineflayer)\n    else if (itemName.includes('axe')) await ensureAxe(mineflayer)\n    await equip(mineflayer, itemName)\n  } else {\n    throw err\n  }\n}","preventionTips":["Pre-check with getItemCount(mineflayer, itemName) > 0 before calling equip.","Run the matching ensure* helper for tool/armor items before equip.","Sleep ~200ms after a craft before equip to let the inventory slot event propagate.","Use exact item names from mineflayer.bot.registry.itemsByName to avoid substring mismatches."],"tags":["minecraft","inventory","equip","item-not-found","validation"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}