{"record":{"id":"e53fd8b20454006d","repo":"moeru-ai/airi","slug":"crafting-failed-e53fd8","errorCode":"CRAFTING_FAILED","errorMessage":"Failed to craft ${itemName}","messagePattern":"Failed to craft (.+?)","errorType":"error_code","errorClass":"ActionError","httpStatus":null,"severity":"error","filePath":"integrations/minecraft/src/skills/crafting.ts","lineNumber":54,"sourceCode":"  }\n\n  // Helper function to attempt crafting\n  async function attemptCraft(\n    recipes: Recipe[] | null,\n    craftingTable: Block | null = null,\n  ): Promise<boolean> {\n    if (recipes && recipes.length > 0) {\n      const recipe = recipes[0]\n      try {\n        await mineflayer.bot.craft(recipe, num, craftingTable ?? undefined)\n        logger.log(\n          `Successfully crafted ${num} ${itemName}${craftingTable ? ' using crafting table' : ''\n          }.`,\n        )\n        return true\n      }\n      catch (err) {\n        throw new ActionError('CRAFTING_FAILED', `Failed to craft ${itemName}`, { error: err })\n      }\n    }\n    return false\n  }\n\n  // Helper function to move to a crafting table and attempt crafting with retry logic\n  async function moveToAndCraft(craftingTable: Block): Promise<boolean> {\n    logger.log(`Crafting table found, moving to it.`)\n    const maxRetries = 2\n    let attempts = 0\n    let success = false\n\n    while (attempts < maxRetries && !success) {\n      try {\n        await goToPosition(\n          mineflayer,\n          craftingTable.position.x,\n          craftingTable.position.y,","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/integrations/minecraft/src/skills/crafting.ts#L36-L72","documentation":"Wrapped around any exception thrown by mineflayer.bot.craft(recipe, num, table) inside attemptCraft. The underlying mineflayer craft can fail for many reasons: insufficient materials mid-call, recipe mismatch, inventory full, async interruption, or a transient server desync. The library re-throws as CRAFTING_FAILED with the original error in context to preserve the cause while giving a stable code.","triggerScenarios":"bot.craft rejects because the recipe's required count exceeds available items (race between recipesFor check and craft); inventory fills up during crafting (no free slots); the crafting table block became unavailable (broken/moved) between selection and craft; bot was killed or kicked mid-craft; recipe object stale after a server recipe refresh.","commonSituations":"Inventory nearly full when crafting a stack-producing recipe; concurrent actions modifying inventory; lag spikes causing craft timeout; recipe planner picked a recipe that needs a table but none was passed.","solutions":["Free inventory slots before crafting (deposit to chest or drop items).","Re-fetch recipes immediately before craft: const r = mineflayer.bot.recipesFor(id, null, num, table); then craft.","Inspect err.context.error (the wrapped Error) for the true cause — 'Not enough space' vs 'Not enough ingredients' have different fixes.","Retry once after a short delay if the cause looks transient (desync); ensure table is still present."],"exampleFix":"// before\ntry { await craftRecipe(mineflayer, 'stick', 4) } catch (e) {}\n\n// after\ntry {\n  await craftRecipe(mineflayer, 'stick', 4)\n} catch (e) {\n  if (e instanceof ActionError && e.code === 'CRAFTING_FAILED') {\n    logger.error('underlying cause:', e.context?.error)\n    // free inventory, then retry once\n    await depositOverflow(mineflayer)\n    await craftRecipe(mineflayer, 'stick', 4)\n  } else throw e\n}","handlingStrategy":"retry","validationCode":"async function canCraftNow(mineflayer: Mineflayer, itemId: number, num: number, table: Block | null): Promise<boolean> {\n  const recipes = mineflayer.bot.recipesFor(itemId, null, num, table)\n  return !!recipes && recipes.length > 0\n}","typeGuard":null,"tryCatchPattern":"try {\n  await craftRecipe(mineflayer, itemName, num)\n} catch (e) {\n  const cause = (e as ActionError).context?.error as Error | undefined\n  if (e instanceof ActionError && e.code === 'CRAFTING_FAILED') {\n    // free inventory, re-fetch recipes, retry once\n    await depositOverflow(mineflayer)\n    await craftRecipe(mineflayer, itemName, num)\n  } else throw e\n}","preventionTips":["Keep at least one free inventory slot per craft operation.","Re-fetch recipes immediately before bot.craft — recipesFor is a snapshot.","Inspect context.error to distinguish 'inventory full' from 'missing ingredient'.","Avoid concurrent inventory mutations while a craft is in flight."],"tags":["minecraft","crafting","inventory","retry","error-wrapping"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}