{"record":{"id":"e06664c9a0b3104e","repo":"alibaba/page-agent","slug":"tool-execution-error","errorCode":"TOOL_EXECUTION_ERROR","errorMessage":"Tool execution failed: ${(error as Error)?.message}","messagePattern":"Tool execution failed: (.+?)","errorType":"exception","errorClass":"InvokeError","httpStatus":null,"severity":"error","filePath":"packages/llms/src/OpenAIClient.ts","lineNumber":243,"sourceCode":"\t\tconst validation = tool.inputSchema.safeParse(parsedArgs)\n\t\tif (!validation.success) {\n\t\t\tconsole.error(z.prettifyError(validation.error))\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.INVALID_TOOL_ARGS,\n\t\t\t\t'Tool arguments validation failed',\n\t\t\t\tvalidation.error,\n\t\t\t\tdata\n\t\t\t)\n\t\t}\n\t\tconst toolInput = validation.data\n\n\t\t// 5. Execute tool\n\t\tlet toolResult: unknown\n\t\ttry {\n\t\t\ttoolResult = await tool.execute(toolInput)\n\t\t} catch (error: unknown) {\n\t\t\tif ((error as any)?.name === 'AbortError') throw error\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.TOOL_EXECUTION_ERROR,\n\t\t\t\t`Tool execution failed: ${(error as Error)?.message}`,\n\t\t\t\terror,\n\t\t\t\tdata\n\t\t\t)\n\t\t}\n\n\t\t// Return result\n\t\treturn {\n\t\t\ttoolCall: {\n\t\t\t\tname: toolCallName,\n\t\t\t\targs: toolInput,\n\t\t\t},\n\t\t\ttoolResult,\n\t\t\tusage: {\n\t\t\t\tpromptTokens: data.usage?.prompt_tokens ?? 0,\n\t\t\t\tcompletionTokens: data.usage?.completion_tokens ?? 0,\n\t\t\t\ttotalTokens: data.usage?.total_tokens ?? 0,","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/alibaba/page-agent/blob/d02db1ee7c41f5315beda88bab2fe935c580f662/packages/llms/src/OpenAIClient.ts#L225-L261","documentation":"The tool's own execute() function threw while running; invoke() rethrows it as InvokeError TOOL_EXECUTION_ERROR with the original error attached, unless it is an AbortError (cancellation), which is rethrown as-is. This is the tool's runtime failure, not an LLM protocol issue.","triggerScenarios":"await tool.execute(toolInput) rejects: e.g. a DOM action tool failing because the element index no longer exists, a network tool timing out, or any bug inside the tool implementation.","commonSituations":"PageController element index stale after page changed between updateTree and click; tool code accessing undefined properties; external services down; passing invalid (schema-valid but semantically wrong) values to the tool.","solutions":["Read the wrapped message and error.cause stack to find which tool failed and why","Fix the tool's internal error (null checks, stale index handling, retries inside the tool)","In agent loops, catch TOOL_EXECUTION_ERROR and feed the message back to the LLM so it can correct course","AbortError is intentionally rethrown — don't swallow it when implementing cancellation"],"exampleFix":"// before\nconst result = await agent.next() // tool throws, whole run crashes\n\n// after\ntry {\n  const result = await agent.next()\n} catch (e) {\n  if (e.code === 'TOOL_EXECUTION_ERROR') {\n    messages.push({ role: 'tool', content: `Error: ${e.message}` }) // let LLM retry\n  } else throw e\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"function isToolExecutionError(e: unknown): e is InvokeError {\n  return e instanceof InvokeError && e.code === InvokeErrorTypes.TOOL_EXECUTION_ERROR\n}","tryCatchPattern":"try {\n  await agent.next()\n} catch (e) {\n  if (isToolExecutionError(e)) {\n    conversation.push({ role: 'tool', content: `Error: ${e.message}` }) // let the model recover\n    return await agent.next()\n  }\n  throw e\n}","preventionTips":["Never swallow AbortError — rethrow it to preserve cancellation","Make tools defensive (validate element freshness, null checks)","Return error messages as tool results instead of throwing when recoverable"],"tags":["tool-execution","llm","agent-loop","runtime-error"],"backgroundTag":"tool-execution-failed","analyzedSha":"d02db1ee7c41f5315beda88bab2fe935c580f662","analyzedAt":"2026-08-28T19:39:48.634Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}