moeru-ai/airi · error · ActionError
CRAFTING_FAILED
CRAFTING_FAILED
Error message
Failed to craft ${itemName} What it means
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.
Source
Thrown at integrations/minecraft/src/skills/crafting.ts:54
}
// Helper function to attempt crafting
async function attemptCraft(
recipes: Recipe[] | null,
craftingTable: Block | null = null,
): Promise<boolean> {
if (recipes && recipes.length > 0) {
const recipe = recipes[0]
try {
await mineflayer.bot.craft(recipe, num, craftingTable ?? undefined)
logger.log(
`Successfully crafted ${num} ${itemName}${craftingTable ? ' using crafting table' : ''
}.`,
)
return true
}
catch (err) {
throw new ActionError('CRAFTING_FAILED', `Failed to craft ${itemName}`, { error: err })
}
}
return false
}
// Helper function to move to a crafting table and attempt crafting with retry logic
async function moveToAndCraft(craftingTable: Block): Promise<boolean> {
logger.log(`Crafting table found, moving to it.`)
const maxRetries = 2
let attempts = 0
let success = false
while (attempts < maxRetries && !success) {
try {
await goToPosition(
mineflayer,
craftingTable.position.x,
craftingTable.position.y,View on GitHub (pinned to 27111382b4)
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.
Example fix
// before
try { await craftRecipe(mineflayer, 'stick', 4) } catch (e) {}
// after
try {
await craftRecipe(mineflayer, 'stick', 4)
} catch (e) {
if (e instanceof ActionError && e.code === 'CRAFTING_FAILED') {
logger.error('underlying cause:', e.context?.error)
// free inventory, then retry once
await depositOverflow(mineflayer)
await craftRecipe(mineflayer, 'stick', 4)
} else throw e
} Defensive patterns
Strategy: retry
Validate before calling
async function canCraftNow(mineflayer: Mineflayer, itemId: number, num: number, table: Block | null): Promise<boolean> {
const recipes = mineflayer.bot.recipesFor(itemId, null, num, table)
return !!recipes && recipes.length > 0
} Try / catch
try {
await craftRecipe(mineflayer, itemName, num)
} catch (e) {
const cause = (e as ActionError).context?.error as Error | undefined
if (e instanceof ActionError && e.code === 'CRAFTING_FAILED') {
// free inventory, re-fetch recipes, retry once
await depositOverflow(mineflayer)
await craftRecipe(mineflayer, itemName, num)
} else throw e
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/e53fd8b20454006d.
Report an issue: GitHub.