moeru-ai/airi · error · Error

Select this tool before running it again.

Error message

Select this tool before running it again.

What it means

rerunToolCall re-executes a previously stored tool call. Some tools are gated by requiresToolSelection: the caller must pass a tools list containing the tool being rerun. If the payload's tools array does not include payload.toolName, the store refuses to run it — the user must explicitly select/enable the tool before rerunning.

Solutions

  1. Include the tool in payload.tools when calling rerunToolCall (the UI should pass the currently enabled tool definitions).
  2. Have the user enable/select the tool in the chat UI before retrying.
  3. Check requiresToolSelection(toolName) beforehand and prompt for selection instead of calling.
  4. Verify the tool name string matches the registered tool's name exactly.

Example fix

// before
await rerunToolCall({ sessionId, toolName: 'web_search' })
// after
await rerunToolCall({ sessionId, toolName: 'web_search', tools: enabledTools })
Defensive patterns

Strategy: validation

Validate before calling

const canRerun = !requiresToolSelection(payload.toolName)
  || payload.tools?.some(t => t.name === payload.toolName)
if (!canRerun) enableToolFirst(payload.toolName)

Try / catch

try {
  await rerunToolCall(payload)
} catch (e) {
  if (e.message === 'Select this tool before running it again.')
    ui.promptToolSelection(payload.toolName)
  else throw e
}

Prevention

When it happens

Trigger: Calling rerunToolCall({ toolName, ... }) where requiresToolSelection(toolName) is true and payload.tools is undefined or does not contain an entry with name === toolName.

Common situations: A UI 'retry this tool call' button that reruns without sending the currently enabled tool list; a tool disabled in settings after its original run; programmatically rerunning a gated tool without reconstructing the tools payload.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of moeru-ai/airi@438a067dde (2026-09-17). Data as JSON: /api/errors/7f03ffda025b481c. Report an issue: GitHub.

Appendix: source

Thrown at packages/stage-ui/src/stores/chat.ts:500

    try {
      return await executeSend({
        sessionId: payload.sessionId,
        text,
        replyToMessageId: sourceMessage?.replyToMessageId,
        tools: payload.tools ?? sourceMessage?.tools?.filter(tool => !requiresToolSelection(tool.name)),
      })
    }
    catch (error) {
      appendSendError(payload.sessionId, error)
      throw error
    }
  }

  /** Runs one stored tool call again and replaces its stored result. */
  async function rerunToolCall(payload: ChatToolCallRerunPayload): Promise<void> {
    if (requiresToolSelection(payload.toolName) && !payload.tools?.some(tool => tool.name === payload.toolName))
      throw new Error('Select this tool before running it again.')

    if (!await chatSession.loadSession(payload.sessionId))
      throw new Error('Failed to load the target chat session')

    const nextMessages = await executeToolCallRerun({
      messages: chatSession.getSessionMessages(payload.sessionId),
      payload,
      resolveTools: () => resolveLlmTools({
        customTools: llmToolsStore.getToolsByNames(payload.toolName),
      }),
    })
    chatSession.setSessionMessages(payload.sessionId, nextMessages)
  }

  /** Clears one session and stops runtime work that still belongs to it. */
  function cleanup(sessionId: string) {
    chatSession.cleanupMessages(sessionId)
    chatContext.resetContexts()

View on GitHub (pinned to 438a067dde)