Skip to content
WebMCP Agents
Esc
↑↓navigate↵open⌘Jpreview
On this page

Errors

Every failed tool call carries one of seven error codes, readable by the model and by code, so the agent knows whether to retry, fix its input or ask the person.

A tool’s failure is not an exception that ends the run. It is a result the agent reads, and the same text the person sees on the page. Every failure says why with one code, in two places:

  • In the text every model reads: Error [invalid_input]: Invalid input for add_to_cart: qty: Too small
  • In structuredContent.error, as { code, retryable }, for the devtools, the chat and any code that branches on it.

The codes

Code Means The agent should
cancelled the person stopped it stop; retry only if asked
interrupted the page navigated, or the tool changed mid-call check the page, then retry
timeout no answer in time (it may or may not have worked) check the page, then retry or try another way
unavailable no such tool on this page right now get to the page that has it
invalid_input the arguments were wrong fix them and retry
needs_user the person has to choose or confirm ask them
failed the tool could not do it read the message

Choosing the code

Throw a WebToolError with a code and a message that says how to fix it:

import { WebToolError } from "@webmcp-agents/core";

execute: ({ slug }) => {
  const product = findProduct(slug);
  if (!product) throw new WebToolError("invalid_input", `No product "${slug}". Try search_products.`);
  if (!product.inStock) throw new WebToolError("failed", `${product.name} is out of stock.`);
  // …
};

Codes you do not choose are filled in for you:

Situation Code
Any other throw failed
Input that fails the schema invalid_input
A confirmation with nothing to click, or with several controls that match its name unavailable
The page changed under the call interrupted

Calling a tool yourself

A call you make with invoke rejects with a WebToolError that carries the same code, so try { await tool.invoke(…) } catch (err) { err.code } reads what an agent would have read. A form’s validation error is the agent’s answer too: see Tools with input. A declarative form answers with text that starts with the code.

Time limits and waiting for the person

The chat stops a tool that has not answered in 30 s (TOOL_TIMEOUT_MS) with timeout, and cancels the call. That clock stops for good once the tool waits for the person, either on a confirmation or because the tool called waitingForUser:

import { waitingForUser } from "@webmcp-agents/core";

waitingForUser("pick_seat", "Choose a seat on the map");

Reading codes in your own code

import { toolError, toolErrorCode } from "@webmcp-agents/core";

const result = toolError("unavailable", "The cart is closed. Use open_cart first.");
toolErrorCode(result); // "unavailable"

Reference: toolError, WebToolError, errorResult.

Was this page helpful?