Skip to content

Errors

Every non-2xx response from POST /v1/interactions maps to one of a small set of typed exceptions, no matter which client makes the call. This page covers the mapping itself and how each surface presents an error once it happens.

The Python SDK’s raise_for_status() maps status codes to exception types; every exception it raises derives from TelemError and carries .message, .status_code, and .body:

HTTP status Exception Meaning
400 BadRequestError Malformed request — e.g. an unknown provider name
401 / 403 AuthError Missing or invalid credentials
404 NotFoundError The resource (e.g. a session id) doesn’t exist
any other non-2xx APIStatusError Everything else, including 5xx — there is no dedicated exception per status beyond the four above

There is currently no dedicated exception for 429 — a rate-limited response would raise the generic APIStatusError like any other unlisted status code. See Rate limits for the current state of rate limiting.

The error message includes the response body’s detail field when present — a plain string, or, for FastAPI validation errors, each item’s msg joined with ", ".

Two failures never reach a status code at all, because no HTTP response was received to map:

Exception Raised when
TelemConnectionError The request timed out or the transport failed before any response arrived
TelemServerVersionError The server answered without the V2 normalized contract 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)

This table is the same one on the Python SDK page — it’s reproduced here because it’s the ground truth for every Telem surface, not just the SDK: the MCP server, the agent-tool plugins, and any client calling the HTTP API directly all see the same status codes for the same reasons.

OpenClaw, opencode, and pi each wire up telem_search and telem_fetch as agent tools on top of the same POST /v1/interactions endpoint, and all three handle a failure the same way — there are two distinct cases.

A partial failure renders inline, next to the results that did come back. When one provider in a search (or one URL in a telem_fetch batch) fails while others succeed, the interaction itself still succeeds — the failure shows up as a line inside the formatted tool result instead of stopping the call:

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

A request-level failure throws. When the POST /v1/interactions call itself returns non-2xx — a 400, 401/403, 404, or 5xx — the tool’s execute() throws a JavaScript Error rather than returning 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>

This is the same shape in all three plugins, and each one has a test that asserts the call rejects rather than returning an error-shaped result. The plugin itself does not catch this throw and turn it into result text — that’s the host’s job. What’s verifiable from the plugin side: OpenClaw’s own persisted transcript format carries an isError flag on tool results, which the plugin reads back out when it rebuilds conversation history for later calls — the standard shape agent hosts use to tell the model “this tool call failed” without stopping the surrounding conversation. In practice this error text is exactly what shows up if you hit it — see the opencode and pi integration pages’ troubleshooting sections, which document recognizing Telem search failed: HTTP 401 or 403 directly.

So: don’t expect a crash from a Telem call failing, but also don’t expect every failure to come back as friendly result text — a request-level failure is a thrown/rejected error, not a formatted message.