{"record":{"id":"e7dc2d5fcea3837a","repo":"chatboxai/chatbox","slug":"tool-batchpart-toolname-is-not-available","errorCode":null,"errorMessage":"Tool \"${batchPart.toolName}\" is not available","messagePattern":"Tool \"(.+?)\" is not available","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderer/stores/session/orchestration.ts","lineNumber":1287,"sourceCode":"        // time spent waiting for user approval / manual continuation.\n        startTime: Date.now(),\n        duration: undefined,\n      })\n    ),\n    generating: true,\n    cancel: (stoppedAt = Date.now()) => controller.abort(stoppedAt),\n  }\n  await modifyMessage(sessionId, message, false)\n\n  try {\n    const { tools } = await buildToolsForPausedToolCall(session, settings, message)\n    for (const batchPart of batch) {\n      if (controller.signal.aborted) break\n\n      const toolValue = (tools as Record<string, unknown>)[batchPart.toolName]\n      const executableTool = toolValue && typeof toolValue === 'object' ? (toolValue as ExecutableTool) : undefined\n      if (typeof executableTool?.execute !== 'function') {\n        throw new Error(`Tool \"${batchPart.toolName}\" is not available`)\n      }\n\n      try {\n        // Bind approval to the exact call the user reviewed. Never infer authorization from\n        // batch membership: a sibling call must pass through its own approval gate.\n        const result = await executableTool.execute(\n          batchPart.args,\n          createPausedToolCallExecutionContext(batchPart, approvedToolCallId, controller.signal)\n        )\n        message = updateToolCallPart(message, batchPart.toolCallId, (toolPart) => ({\n          ...toolPart,\n          state: 'result',\n          pauseReason: undefined,\n          result,\n          duration: toolPart.startTime ? Date.now() - toolPart.startTime : undefined,\n        }))\n      } catch (error) {\n        if (controller.signal.aborted) {","sourceCodeStart":1269,"sourceCodeEnd":1305,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/renderer/stores/session/orchestration.ts#L1269-L1305","documentation":"Thrown during batched execution of paused tool calls. After the user approves a paused batch, buildToolsForPausedToolCall rebuilds the toolset and each batch part is dispatched by name; if tools[batchPart.toolName] is absent or lacks an execute function, the call cannot run and the batch is aborted. This guards against dispatching a tool the session no longer exposes.","triggerScenarios":"buildToolsForPausedToolCall returns a tools map that does not include batchPart.toolName or includes a non-executable entry. Causes: settings changed between pause and approval (tool disabled, agent mode toggled off, knowledge base detached), the model emitted a tool name not in the allowed set, or a version change renamed/removed a tool.","commonSituations":"User paused on a tool call then changed settings (disabled agent mode, removed knowledge base, switched provider) before approving; a model hallucinated a tool name; a plugin/tool was unregistered in an update while a paused call waited.","solutions":["Re-validate each batchPart.toolName against the rebuilt tools map and mark only missing ones as errored instead of aborting the whole batch.","Prompt the user to re-resume after settings changes rather than failing silently.","Keep tool names stable across versions and deprecate rather than rename.","Log the available tool keys alongside the missing name to speed diagnosis."],"exampleFix":"// before\nconst toolValue = (tools as Record<string, unknown>)[batchPart.toolName]\nconst executableTool = toolValue && typeof toolValue === 'object' ? (toolValue as ExecutableTool) : undefined\nif (typeof executableTool?.execute !== 'function') {\n  throw new Error(`Tool \"${batchPart.toolName}\" is not available`)\n}\n// after\nconst toolValue = (tools as Record<string, unknown>)[batchPart.toolName]\nconst executableTool = toolValue && typeof toolValue === 'object' ? (toolValue as ExecutableTool) : undefined\nif (typeof executableTool?.execute !== 'function') {\n  message = updateToolCallPart(message, batchPart.toolCallId, (p) => ({ ...p, state: 'error', result: { error: `Tool \"${batchPart.toolName}\" is no longer available (settings changed?)` } }))\n  continue\n}","handlingStrategy":"validation","validationCode":"const { tools } = await buildToolsForPausedToolCall(session, settings, message)\nconst missing = batch.filter((p) => typeof (tools as Record<string, unknown>)[p.toolName]?.execute !== 'function')\nif (missing.length) {\n  // mark only those parts as errored, continue the rest\n}","typeGuard":"function isExecutableTool(v: unknown): v is { execute: (...args: unknown[]) => Promise<unknown> } {\n  return typeof v === 'object' && v !== null && typeof (v as { execute?: unknown }).execute === 'function'\n}","tryCatchPattern":"try {\n  await runBatch()\n} catch (err) {\n  if (err instanceof Error && /is not available$/.test(err.message)) {\n    markToolPartsErrored(message, batch)\n  } else throw err\n}","preventionTips":["Re-validate tool names against the rebuilt toolset and error per-part, not the whole batch.","Keep tool identifiers stable across versions.","Warn the user when settings changed since the call was paused."],"tags":["tools","agent-mode","paused-call","settings","orchestration"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}