moeru-ai/airi · warning · Error

Action queue full (${queueSize}/${MAX_QUEUED_CONTROL_ACTIONS

Error message

Action queue full (${queueSize}/${MAX_QUEUED_CONTROL_ACTIONS}). Use stop() or wait for completion.

What it means

Thrown by Brain.enqueueControlAction when the pending control-action queue plus any active action reaches MAX_QUEUED_CONTROL_ACTIONS (defined as 5 at brain.ts:229). Async control actions are serialized through a single worker, so this guard prevents unbounded backlog. The message tells the caller to stop() or wait.

Source

Thrown at integrations/minecraft/src/cognitive/conscious/brain.ts:1173

    const cleared = this.pendingControlActions.splice(0, this.pendingControlActions.length)
    for (const entry of cleared) {
      entry.state = state
      entry.finishedAt = clearedAt
      entry.error = state === 'failed' ? entry.error : entry.error ?? 'Cleared from action queue'
      this.pushRecentControlAction(entry)
    }
    this.touchActionQueue()
    return cleared.length
  }

  private async enqueueControlAction(
    bot: MineflayerWithAgents,
    action: ActionInstruction,
    sourceTurnId: number,
  ): Promise<unknown> {
    const queueSize = this.pendingControlActions.length + (this.activeControlAction ? 1 : 0)
    if (queueSize >= MAX_QUEUED_CONTROL_ACTIONS) {
      throw new Error(`Action queue full (${queueSize}/${MAX_QUEUED_CONTROL_ACTIONS}). Use stop() or wait for completion.`)
    }

    const entry: ControlActionQueueEntry = {
      id: ++this.nextControlActionId,
      action: {
        tool: action.tool,
        params: this.cloneActionParams(action.params),
      },
      sourceTurnId,
      state: 'pending',
      enqueuedAt: Date.now(),
    }
    this.pendingControlActions.push(entry)
    this.touchActionQueue()

    this.appendLlmLog({
      turnId: sourceTurnId,
      kind: 'scheduler',

View on GitHub (pinned to 27111382b4)

Solutions

  1. Call brain.stop() to cancel the active action and clear pending ones before issuing new work.
  2. Wait for the current action to complete (await the enqueueControlAction promise / poll getActionQueueSnapshot).
  3. Throttle the planner so it does not enqueue a new async action while queueSize is near the cap.
  4. Investigate why the active action is not completing if the queue stays full (pathfinder deadlock, stuck entity).
Defensive patterns

Strategy: validation

Validate before calling

function canEnqueue(brain) {
  const counts = brain.getActionQueueSnapshot().counts
  const size = counts.pending + (counts.active ? 1 : 0)
  return size < MAX_QUEUED_CONTROL_ACTIONS
}
if (!canEnqueue(brain)) await brain.stop()  // or await completion

Type guard

function queueHasCapacity(brain, max = 5) {
  const c = brain.getActionQueueSnapshot().counts
  return (c.pending + (c.active ? 1 : 0)) < max
}

Try / catch

try {
  await brain.enqueueControlAction(bot, action, turnId)
} catch (e) {
  if (e.message.startsWith('Action queue full'))
    await brain.stop()  // clear backlog then retry
  throw e
}

Prevention

When it happens

Trigger: The LLM/cognitive loop issues async actions faster than the worker drains them (e.g. repeated collectBlocks while pathfinding is slow); a stuck active action never completes, filling the queue with subsequent turns; stop() was not called before a new burst of actions.

Common situations: Long-running navigation/mining actions stacking up while the planner keeps emitting new ones; a deadlocked pathfinder holding the active slot; insufficient backpressure between the planner and the action worker.

Related errors


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