Skip to content

Resources

Errors

How Telem reports failures: typed SDK exceptions, the HTTP status for each, and how the agent plugins and the MCP server show a failed call.

Use this page to find out what a failed Telem call means. Every non-2xx response from Search or Fetch maps to one of a few typed exceptions. This is the same for every client.

In the Python SDK, raise_for_status() does the mapping. Every exception derives from TelemError and has .message, .status_code and .body:

HTTP status Exception Meaning
400 BadRequestError Malformed request. Example: an unknown provider name
401 AuthError Missing or invalid API key
402 APIStatusError The account cannot pay for the call: the billing subscription is suspended, or the prepaid credit is used up. The message says which. Fetch and monitors give the code payment_required
403 AuthError The key is valid but is not allowed to make this call
403, body not JSON APIStatusError A firewall blocked the request before it reached Telem. The key is not the problem. The request text can have characters that are not allowed
404 NotFoundError The resource (e.g. a session id) doesn’t exist
405 APIStatusError The endpoint does not take this HTTP method. Example: GET /v1/fetch. Fetch and monitors give the code method_not_allowed
409 APIStatusError missing_snapshots: the request leaves out earlier conversation context that Telem does not have. Nothing ran; send it again with that context
422 APIStatusError The body failed validation. Example: an auto_routing value other than accuracy
429 APIStatusError A per-minute limit: the account’s (by default 6,000 search queries or fetched URLs a minute), or the key’s, if one was set. The message says which. Wait for the seconds in Retry-After, then try again
502 APIStatusError Fetch only. provider_unavailable: you pinned providers and every URL failed before its page was reached
503 APIStatusError Search: all_providers_failed, every provider call failed (Retry-After: 1 when a retry can help). With a plain-string message: Telem turned the request away before it ran; try again later
504 APIStatusError deadline_exceeded: too little time was left to start any provider call. Safe to retry with backoff
any other non-2xx APIStatusError Everything else, including 500

For the limits behind a 429, see Rate limits. For what a call costs, see Pricing.

The SDK takes its error message from the error body. The message is error.message, or the detail string. For validation errors, it is each item’s msg, joined with ", ". When detail is an object, the message is only Unexpected status code N. Read the code from exc.body["detail"]["code"].

Two failures have no status code, because no HTTP response arrived:

Exception Raised when
TelemConnectionError The request timed out or the transport failed before any response arrived
TelemTimeoutError A TelemConnectionError for a timeout. Telem can have received the request. After a monitor create, list your monitors before you try again
TelemServerVersionError The router answered without the normalized response the SDK requires (normalized_schema_version < 2)
from telem import Telem, BadRequestError
try:
Telem().search("hi", providers_include=["does-not-exist"])
except BadRequestError as exc:
print(exc.status_code, exc.message)

The status codes in the first table apply to every Telem surface. The MCP server, the agent-tool plugins and any client that calls the HTTP API directly all get the same status codes for the same reasons.

The hosted MCP server also checks every request before any tool runs. When the first request fails, your MCP client cannot connect:

  • 401: the API key is missing or not valid, or the server could not check it.
  • 400: an X-Telem-* header has a value the server does not accept.
  • 413: the request body is over 1,000,000 bytes.
  • 503: the MCP server is not turned on for this deployment.

A Search error has a detail field. It is a string, a list of validation errors, or an object with a code. You get the object for 409, 503 and 504:

{"detail": {"code": "all_providers_failed", "reason": "provider_errors"}}

Fetch and monitors answer with an error object:

{"error": {"code": "invalid_request", "message": "...", "param": "urls[1]"}}

Check code in your code, because the message text can change. When param is present, it names the field that is not correct.

Only fetch (/v1/fetch) and monitors (/v1/monitors) use the error object. Search (/v1/search and /v1/interactions) and every other route keep the older detail shape. This includes a route under /v1/ that does not exist, which gives 404 with {"detail": "Not Found"}. Telem keeps the older shape on these routes so that existing clients do not break. The Python and JavaScript SDKs read both shapes. If you call the HTTP API directly, check for both error and detail.

OpenClaw, OpenCode, Pi and DeepSeek Harness each build telem_search and telem_fetch on the same two endpoints. All four handle a failure in the same way. There are two cases.

A partial failure shows inline. It shows next to the results that came back. If one provider in a search fails and others succeed, the interaction still succeeds. The same is true for one URL in a telem_fetch batch. The failure shows as a line in the formatted tool result:

  • Search: [provider] failed: <message>
  • Fetch: a ### <url> section with Error: <type>: <message> in place of the page content

The hosted MCP server, which Claude Code, Codex and other MCP clients use, shows a failed search provider with the same [provider] failed: <message> line. A provider whose results could not be read gets [provider] no rows (<reason>).

A request-level failure throws. When the POST itself returns a non-2xx status, the tool’s execute() throws a JavaScript Error. It returns no formatted text:

Telem search failed: HTTP 401 <first 200 characters of the response body>
Telem fetch failed: HTTP 401 <first 200 characters of the response body>

The plugin does not catch that throw or turn it into result text. That is the host’s job. OpenClaw’s saved transcript has an isError flag on tool results. The plugin reads this flag back when it rebuilds the conversation history. This flag is the standard way for a host to tell the model that a tool call failed without stopping the conversation.

The Hermes plugin shows a failed provider or URL in the same way. A request-level failure comes back as a Python SDK error instead, with the server’s message, such as Invalid API key.

Claude Code, Codex and other MCP clients use the hosted MCP server, which works differently. It shows no line for a failed provider: the results of the providers that succeeded come back alone, and when every provider fails, the model sees No results found. When the request itself fails, the tool returns error text, for example The Telem router rejected the request (HTTP <status>) for an HTTP error.

Was this page helpful?