{"record":{"id":"669a35d66f0c5d54","repo":"moeru-ai/airi","slug":"action-limit-exceeded-max-this-maxactionspertur","errorCode":null,"errorMessage":"Action limit exceeded: max ${this.maxActionsPerTurn} actions per turn","messagePattern":"Action limit exceeded: max (.+?) actions per turn","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"integrations/minecraft/src/cognitive/conscious/js-planner.ts","lineNumber":1408,"sourceCode":"    const params: Record<string, unknown> = {}\n    for (const [index, key] of keys.entries()) {\n      if (index >= args.length)\n        break\n      params[key] = args[index]\n    }\n\n    return params\n  }\n\n  private async runAction(tool: string, params: Record<string, unknown>): Promise<ActionRuntimeResult> {\n    if (!this.activeRun)\n      throw new Error('Tool calls are only allowed during REPL evaluation')\n\n    if (this.activeRun.sawSkip && tool !== 'skip')\n      throw new Error('skip() cannot be mixed with other tool calls in the same script')\n\n    if (this.activeRun.actionCount >= this.maxActionsPerTurn)\n      throw new Error(`Action limit exceeded: max ${this.maxActionsPerTurn} actions per turn`)\n\n    if (tool === 'skip')\n      this.activeRun.sawSkip = true\n\n    this.activeRun.actionCount++\n\n    if (tool === 'skip') {\n      const action: ActionInstruction = { tool: 'skip', params: {} }\n      const runtimeResult: ActionRuntimeResult = {\n        action,\n        ok: true,\n        result: 'Skipped turn',\n      }\n      this.activeRun.executed.push(runtimeResult)\n      return runtimeResult\n    }\n\n    const validation = this.validateAction(tool, params)","sourceCodeStart":1390,"sourceCodeEnd":1426,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/integrations/minecraft/src/cognitive/conscious/js-planner.ts#L1390-L1426","documentation":"Thrown by JavaScriptPlanner.runAction() when this.activeRun.actionCount has already reached this.maxActionsPerTurn (constructor default 5, configurable via options.maxActionsPerTurn). Each tool invocation increments actionCount including skip. The limit prevents runaway scripts from spawning unbounded Minecraft actions in a single turn.","triggerScenarios":"A script loops calling use() more than maxActionsPerTurn times; a long sequential plan in one script instead of across turns; skip counting against a tight budget after several real actions; maxActionsPerTurn lowered via options while the prompt still encourages long scripts.","commonSituations":"Model writes a for-loop over many targets in a single turn; budget too low for the task; repeatedly retrying failed actions until the limit is hit; not splitting work across turns.","solutions":["Split the work across multiple planner turns instead of one large script.","Raise maxActionsPerTurn in the JavaScriptPlannerOptions if the task genuinely needs more actions per turn.","Break out of loops once the goal is achieved rather than consuming the whole budget.","Prefer batch-capable actions (e.g. collectBlocks with a count) over repeated single calls."],"exampleFix":"// before\n//   for (const p of manyTargets) { await use('mineBlockAt', { position: p }) }  // throws at #6\n//\n// after (option A — raise the limit)\n//   new JavaScriptPlanner({ maxActionsPerTurn: 12 })\n// after (option B — split across turns)\n//   await use('mineBlockAt', { position: manyTargets[0] })  // continue next turn","handlingStrategy":"validation","validationCode":"// Track calls against the budget before each use():\n// let calls = 0\n// const BUDGET = 5  // match maxActionsPerTurn\n// function budgetedUse(name: string, params = {}) {\n//   if (calls >= BUDGET) { log('action budget exhausted; defer to next turn'); return skip() }\n//   calls++\n//   return use(name, params)\n// }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Split long plans across multiple planner turns.","Raise maxActionsPerTurn in JavaScriptPlannerOptions only if the task truly needs it.","Break loops once the goal is met instead of burning the budget.","Prefer batch actions (e.g. collectBlocks with num) over repeated single calls."],"tags":["llm-planner","runtime","action-limit","budget"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}