con un clic
build-error-adapter
// Build new Arcade error adapters from scratch using public Arcade TDK patterns. Use when adding provider integrations, mapping SDK exceptions, or extending HTTP/GraphQL/auth adapter behavior.
// Build new Arcade error adapters from scratch using public Arcade TDK patterns. Use when adding provider integrations, mapping SDK exceptions, or extending HTTP/GraphQL/auth adapter behavior.
| name | build-error-adapter |
| description | Build new Arcade error adapters from scratch using public Arcade TDK patterns. Use when adding provider integrations, mapping SDK exceptions, or extending HTTP/GraphQL/auth adapter behavior. |
Use this workflow to create new error adapters that fit Arcade TDK conventions.
Start here and align behavior with this doc:
arcade_tdk.error_adapters.base.ErrorAdapterarcade_tdk.errors.UpstreamError — upstream responded with an HTTP status codearcade_tdk.errors.UpstreamRateLimitError — 429 / quota-exhausted with retry_after_msarcade_tdk.errors.NetworkTransportError — no complete response was received
(timeouts, connection/DNS/TLS failures, decoding errors, redirect exhaustion).
status_code is always None; use one of the NETWORK_TRANSPORT_RUNTIME_*
kinds: _TIMEOUT, _UNREACHABLE, _UNMAPPED.arcade_tdk.errors.FatalToolError — unrecoverable tool-authoring bug or
environment misconfiguration (invalid URL, unsupported protocol, bad headers,
TLS trust failures). Never retried.arcade_tdk.errors.RetryableToolError — transient tool-body failure with a
hint for the LLM to retry.arcade_tdk.errors.ContextRequiredToolError — needs human input before retry.slug class attributefrom_exception(self, exc: Exception) -> ToolRuntimeError | NoneNone when the exception is not recognized for that adapter.ToolRuntimeError subclass for recognized exceptions (UpstreamError, UpstreamRateLimitError, etc.).message must be safe.developer_message when needed.If you are not fully sure what str(exc), vendor reason, or nested payload fields can contain, treat them as potentially sensitive.
"Upstream <Service> request failed with status code <code>.""Upstream <Service> error: unhandled <ExceptionType>."developer_message instead of message.message (status code, error class, stable provider error code).message.Use this decision rule:
message.message; include only in developer_message.message; sanitize or omit even in developer_message if policy requires.When in doubt, prefer slightly less detail in message and richer diagnostics in developer_message.
Use an error adapter when:
Raise explicit tool errors in tool code when:
RetryableToolError).ContextRequiredToolError).from arcade_core.errors import ToolRuntimeError
class VendorErrorAdapter:
slug = "_vendor"
def from_exception(self, exc: Exception) -> ToolRuntimeError | None:
# recognize typed vendor exceptions
# return mapped ToolRuntimeError
return None
except Exception handling inside from_exception.Example ordering:
For adapted errors:
extra["service"] = self.slugextra["error_type"] = type(exc).__name__ for non-status failuresUpstream responded with an HTTP status code → UpstreamError:
UpstreamRateLimitError with retry_after_msUpstreamError (status_code >= 500)UpstreamErrorUpstreamError derives retryability from status code, so predictable behavior is automatic.
No complete response from upstream → NetworkTransportError:
Use this class when the exception inherently means the request never reached the
upstream, or no complete response came back. status_code is None by design.
| Exception kind | kind= | can_retry= |
|---|---|---|
| Timeouts (connect, read, pool) | NETWORK_TRANSPORT_RUNTIME_TIMEOUT | True |
| Connection refused, DNS, TLS handshake, remote-protocol errors | NETWORK_TRANSPORT_RUNTIME_UNREACHABLE | True |
| Decoding failures, generic transport fallback | NETWORK_TRANSPORT_RUNTIME_UNMAPPED | True |
| Redirect-loop exhaustion | NETWORK_TRANSPORT_RUNTIME_UNMAPPED | False |
Tool-authoring bugs / local environment misconfiguration → FatalToolError:
Use this class for exceptions that will never succeed on retry — the tool's code or environment needs to change:
ssl.SSLError and siblings)Do not dress these up as UpstreamError — an UpstreamError implies the
upstream service actually said "no". Miscategorizing pollutes telemetry and
sends the wrong retry signal.
For SDK-specific adapters, lazy-import the SDK module inside from_exception if that dependency may be optional.
None.For httpx and requests, automatic adaptation is typically available.
For SDK-specific adapters, register explicitly on tools.
from arcade_mcp_server import tool
from arcade_tdk.error_adapters import GoogleErrorAdapter
@tool(
# Depending on Arcade version, this may be `adapters=` or `error_adapters=`.
adapters=[GoogleErrorAdapter()],
)
def my_tool(...) -> ...:
...
If your project uses a different parameter name, follow your installed API docs/signature.
Create or extend tests in your project test suite:
ToolRuntimeError subclassstatus_code, kind, can_retryextra keys (service, error_type, endpoint/method when applicable)NoneNonemessage stays safe for uncertain/raw exceptionsdeveloper_message carries deep diagnosticsToolRuntimeError | None