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

Tool errors

Every error from connecting, syncing and calling a tool endpoint, with its cause and fix.

Where errors show

Place Shows
The response to opening the route Connect errors
The endpoint row under Endpoints on Agent → Tools, after Sync failed: Sync errors
median tools list and GET /v1/tool-endpoints The same sync errors, per endpoint
median tools endpoint sync, POST /v1/tool-endpoints/sync, Sync and Change endpoint on the endpoint row Sync request errors
Tool call entries on Logs, request cards in the thread, median tools test Call errors
Your route’s HTTP responses Route responses
Your server’s console when the route loads Load errors

Connect errors

Opening the route with Authorization: Bearer $MEDIAN_KEY connects it. A success looks like this:

{
  "connected": true,
  "endpoint": "https://acme.com/api/median",
  "tools": 2,
  "message": "Connected. Median is syncing 2 tools."
}

tools counts the tools in your config. The sync runs after the response, so check the endpoint row or median tools list for the result.

Code Status Message Fix
unauthorized 401 Send Authorization: Bearer $MEDIAN_KEY to connect this endpoint. Manifest reads and tool calls require a valid median-signature. Send the same key the server holds. The route also answers this when MEDIAN_KEY is not set on the server
invalid_median_key 500 Median: MEDIAN_KEY must start with median_key_. Copy the Median key from Settings under API. Use the Median key, not the browser key
invalid_median_key 500 Median: MEDIAN_KEY is malformed. Copy it again from Settings under API. Copy the whole key again from Settings → API
median_endpoint_unknown 400 Median: MEDIAN_TOOLS_URL is not a URL. Set it to this route’s public address, like https://example.com/api/median. Set MEDIAN_TOOLS_URL to a full URL, such as https://acme.com
median_unreachable 502 Median could not be reached to connect this route. Check the network and open it again. Allow outbound HTTPS from your server to api.median.sh
invalid_api_key 401 That Median key does not match any organization. Copy the median_key_ key again from Settings under API. The key was revoked. Create a key on Settings → API and deploy it
legacy_api_key 400 This is a legacy API key. Create a Median key in Settings under API, set it as MEDIAN_KEY, and try again. Create a Median key
missing_median_key 400 Create a Median key in Settings under API before connecting tools. That key belongs in MEDIAN_KEY on your server. Seen from Add endpoint or the CLI. Create a key first
invalid_url 400 Use an HTTPS URL, or HTTP on localhost for testing. Use https://
invalid_url 400 That address points inside a network, not at the internet. Use a public address, or a tunnel
invalid_url 400 Endpoint URLs have to be 512 characters or fewer. Shorten the URL
invalid_url 400 Enter a valid URL. Fix the URL
duplicate_endpoint 400 An endpoint with this URL is already connected. Seen from Change endpoint. Remove the other endpoint first
too_many_tool_endpoints 400 You can connect 10 tool endpoints at once. Remove one before adding another. Remove an endpoint you no longer use
rate_limited 429 Too many requests. Wait a moment and try again. Wait a minute and open the route again
median_refused_connection Varies Median refused the connection with HTTP <status>. Check MEDIAN_KEY and try again. Check the key and the status

Sync errors

A failed sync keeps the last good tool set. The agent keeps using it.

Message after Sync failed: Cause Fix
The endpoint refused the signature. Open the route once to reconnect it with that deployment’s MEDIAN_KEY. Your route answered 401. It holds a different key than the one this endpoint is bound to Reconnect
The endpoint answered <status>. Any other non-2xx. 404 is usually the wrong path. 500 is often a missing MEDIAN_KEY Check the URL and your server logs
The endpoint did not answer with JSON. Is the URL pointing at the route exported by median()? The URL serves a page, not the route Point it at the route file’s path
The endpoint did not answer. Check the URL and that your server is up. No answer in 10 seconds, or no connection Check the URL, DNS and that the server is up
<origin> is this deployment’s own machine, not yours. Median calls your endpoint from the cloud… The URL is localhost Use a tunnel
The endpoint redirected to <url>, which syncs never follow. Point it there instead. Your server redirects, often apex to www Use the URL in the message
The endpoint redirected, which syncs never follow. A redirect to somewhere Median will not name Use the final URL
That address points inside a network, not at the internet. The URL is a private address Use a public address
The manifest is too large to read. Over 500 KB Cut descriptions or tools
The tool name "x" already comes from <url>. Tool names have to be unique across every endpoint. Another endpoint serves a tool with the same name Rename one, or remove the old endpoint
These endpoints would declare N tools together, and the organization limit is 20. More than 20 tools across endpoints Remove tools or endpoints
tools[0].name "x" is one of the agent’s own tools. Pick another name. A reserved name Rename the tool
tools[0].description is over 500 characters. Description too long Shorten it
tools[0].inputSchema has N fields, and the most a tool can take is 20. Too many inputs Split the tool
tools[0].inputSchema is over 8000 characters. Schema too long, often from long field descriptions or enums Shorten them
The manifest version is N, and this backend speaks version 1. Update @mediansh/agent-tools or Median, whichever is behind. Package and Median disagree Update @mediansh/agent-tools
Could not sync the tools. Try again. Unexpected failure in Median Sync again
Too many requests. Wait a moment and try again. Manual syncs are limited to 60 an hour, bursts of 10 Wait

A hand-rolled endpoint can also fail on the manifest’s shape. Those messages name the field, like tools[2].inputSchema.additionalProperties has to be false. The manifest format is in the tool endpoint reference.

Sync request errors

Asking for a sync can fail before any sync runs. Over the API, no_endpoint and endpoint_required return status 400, and endpoint_not_found returns 404.

Code Message Fix
no_endpoint Connect a tool endpoint before syncing. Connect an endpoint first
endpoint_required Pass the endpoint URL to sync when more than one is connected. Pass a connected endpoint’s URL with --url <url> on median tools endpoint sync, or ?url= on the request
endpoint_not_found No tool endpoint is connected at <url>. Run GET /v1/tool-endpoints to see the ones that are. The url matches no connected endpoint. Check it against median tools list
endpoint_not_found This tool endpoint is no longer available. Refresh the page. Seen from Sync and Change endpoint. The endpoint was removed. Refresh the page

Call errors

Message Cause
The endpoint did not answer in time. No answer in 10 seconds, or the connection failed
The endpoint answered <status>. <code>: <message> Your route answered non-2xx. The code and message come from your error body
The endpoint redirected, which tool calls never follow. Your server redirected the POST
The endpoint answered with too much to read. The body was over 100 KB
The tool failed without saying why. An error envelope with no message
<reason>: <detail> Your tool returned ok: false, known: false, allowed: false or outcome: "blocked". reason defaults to tool_refused
<reason>: <detail> The action may have completed. Inspect its state before retrying and reuse the same tool call id. Your tool returned outcome: "unknown"
The tool is no longer available. An approved request whose tool was switched off, removed, or moved to another endpoint
The tool returned no result. Check whether the action completed before retrying. An approved call or a teammate run reported nothing for 10 minutes. The hourly check marks it, so it can take up to 70 minutes to show
The tool request failed. Check the result before retrying. Median failed while running an approved call

What the agent does when a tool fails

Your endpoint The agent
Returns a result Answers from it in its own words
Returns a refusal from the table above, or execute throws Tells the customer what your reason or message means, and does not retry
Answers non-2xx, times out, redirects, or sends over 100 KB Is told only that the tool is not answering. It says what it knows for sure and hands off. Your error text does not reach it
An approved call fails The thread shows <tool> did not run: <error> and the conversation turns unread. The agent treats the action as not done and hands off rather than promise it

Route responses

What median() answers. Every error uses { "error": { "code", "message" } }.

Code Status Cause
method_not_allowed 405 Not a GET or POST
missing_secret 500 No MEDIAN_KEY on the server and no key option
invalid_median_key 500 MEDIAN_KEY is malformed
missing_signature 401 No median-signature header. A proxy in front of your server may strip it
malformed_signature 401 The header is not t=<ms>,v1=<hex>
stale_timestamp 401 The signature is more than 5 minutes from your server’s clock. Fix the clock
invalid_signature 401 Median signed with a different key. Reconnect
invalid_body 400 The body is not a JSON object, or has no tool
unknown_op 400 Median asked for something this package version does not know. Update @mediansh/agent-tools
unknown_tool 404 Median’s copy lists a tool your deployed config no longer has. Sync
invalid_input 400 The input failed validation. See below
execution_failed 200 execute threw. The message goes back, the stack trace stays on your server
diagnostics_unsupported 200 Median asked for server diagnostics and the config has none. Not a fault

invalid_input messages name the first failing field: x is required., x must be a string., x must be a number., x must be a boolean., x must be one of: a, b., Unexpected field "y". This tool's input allows: x. Validation does not coerce types, and null counts as absent.

Load errors

These throw when the route module loads, so every tool on the route is down until you fix them.

Message Fix
Median: the tool name "x" is invalid. Names start with a letter… A letter, then letters, numbers and underscores, up to 64 characters
Median: the tool "x" has no description… Add one sentence
Median: the tool "x" has risk "y". Use “low”, “medium”, “reviewed” or “high”. Fix the risk
Median: the field "k" on "x" was not built with the schema builder… Use p.string(), p.number(), p.boolean() or p.enum()
Median: the tool "x" has no execute function. Add execute
Median: two plugins both define a tool called "x". Take one of them out. Remove one plugin
Median: your tool "x" has the same name as one from the navigation plugin. Rename yours, or drop the plugin. Rename your tool

navigation() has its own load errors. See Pages and highlights.

Approval and run errors

Code Message
approval_settled This request has already been reviewed.
approval_expired This request expired because the conversation ended.
approval_expired This request expired without a decision.
approval_not_found This request is unavailable in your inbox.
tool_not_found <tool> is not one of your switched on tools.
tool_not_found <tool> is unavailable or disabled. Check its settings in Agent > Tools.
invalid_input Names the field, like “orderNumber is needed to run this.” or “days has to be a number.”
too_many_running Three tools are already running in this conversation. Wait for one to finish.
conversation_archived Move this conversation out of the archive before running a tool.
invalid_request Use conversationId or as, not both. A conversation uses its stored visitor identity.

The rules behind these are in How tool calls run.

The agent does not use a tool

Check How
The endpoint synced The row under Endpoints on Agent → Tools, or median tools list
The tool is on The tool’s switch on Agent → Tools, or median tools enable <name>
The conversation started after your deploy Open conversations keep the last sync. Press Sync in the menu at the end of the endpoint’s row
The description says when to use it The agent picks tools by their description
The turn had calls left The agent sends 3 calls per turn

Common setups

The tunnel URL changed

Median calls your route from the cloud, so a local server needs a tunnel. Each new tunnel hostname connects as a new endpoint. Its tools then clash with the old endpoint’s, and its sync fails with “The tool name “orderStatus” already comes from …“.

Set the address in the server's environment

MEDIAN_TOOLS_URL=https://your-tunnel.example.com

Restart the dev server so it reads the new value.

Open the route once

curl -H "authorization: Bearer $MEDIAN_KEY" http://localhost:3000/api/median

Remove the old endpoint

Use Remove endpoint in the menu at the end of the endpoint’s row, or median tools endpoint remove <id>.

Change endpoint on the old endpoint also works, and keeps each tool’s switch.

Preview deployments add endpoints

Every preview URL that opens the route with the bearer header becomes an endpoint. Its tools clash with production’s, the organization fills toward 10 endpoints, and every endpoint syncs before each new conversation’s first reply. A preview behind a login answers 401 or redirects, and its sync fails.

  • Open the route only from production.
  • Remove preview endpoints on Agent → Tools.

You rotated the Median key

Median signs calls to an endpoint with the key that connected it. After you change MEDIAN_KEY, your route rejects those signatures until you reconnect.

Create the new key

On Settings → API.

Deploy it

Set it as MEDIAN_KEY on your server.

Open the route once with the new key

curl -H "authorization: Bearer $MEDIAN_KEY" https://acme.com/api/median

Revoke the old key

On Settings → API.

If you revoke first, calls fail with invalid_signature and syncs show “The endpoint refused the signature” until you open the route again.

On an edge runtime there is no file system to read routes from. The route logs “Median: navigation() found no pages, so the agent has no way to move anybody.” and serves no goToPage tool. Pass routes to navigation(), or run the route on Node 20.16 or later, or Bun. See Pages and highlights.

Was this page helpful?