From dc7d5439728aaaea5132fde1f0f418f76d0980a7 Mon Sep 17 00:00:00 2001 From: jottakka Date: Thu, 16 Apr 2026 19:19:12 -0300 Subject: [PATCH 1/3] docs: document NetworkTransportError and HTTP adapter routing Adds NetworkTransportError to the error hierarchy diagram and Python reference, describes the three NETWORK_TRANSPORT_RUNTIME_* ErrorKind values, and extends client-side error handling examples (Python, JS, Java) with a NETWORK_TRANSPORT_ branch. Clarifies in the tool-author guide how the HTTP error adapter now splits exceptions between UpstreamError, NetworkTransportError, and FatalToolError. Co-Authored-By: Claude Opus 4.7 (1M context) --- app/_components/error-hierarchy.tsx | 1 + .../error-handling/useful-tool-errors/page.mdx | 6 ++++++ .../guides/tool-calling/error-handling/page.mdx | 15 +++++++++++++++ app/en/references/mcp/python/errors/page.mdx | 8 ++++++++ 4 files changed, 30 insertions(+) diff --git a/app/_components/error-hierarchy.tsx b/app/_components/error-hierarchy.tsx index 625e71934..df6f96f1a 100644 --- a/app/_components/error-hierarchy.tsx +++ b/app/_components/error-hierarchy.tsx @@ -19,6 +19,7 @@ ToolkitError # (Abstract base class) ├── RetryableToolError # Tool can be retried with extra context ├── ContextRequiredToolError # Additional context needed before retry ├── FatalToolError # Unhandled bugs in the tool implementation + ├── NetworkTransportError # No HTTP response received (timeout, DNS, TLS, etc.) └── UpstreamError # HTTP/API errors from external services └── UpstreamRateLimitError # Rate limiting errors from service `} diff --git a/app/en/guides/create-tools/error-handling/useful-tool-errors/page.mdx b/app/en/guides/create-tools/error-handling/useful-tool-errors/page.mdx index 7d408daf1..8384f0e4a 100644 --- a/app/en/guides/create-tools/error-handling/useful-tool-errors/page.mdx +++ b/app/en/guides/create-tools/error-handling/useful-tool-errors/page.mdx @@ -40,6 +40,12 @@ def fetch_data( return response.json() ``` +The HTTP error adapter routes exceptions from `httpx` and `requests` based on whether a complete response was received: + +- **Real HTTP responses** (4xx/5xx) → `UpstreamError` (with `status_code`). 429 becomes `UpstreamRateLimitError`. +- **No response received** (connect/read timeouts, DNS failures, connection errors, TLS handshake failures, decoding errors, redirect-loop exhaustion) → `NetworkTransportError` with `status_code=None`. Classified by `ErrorKind` as `NETWORK_TRANSPORT_RUNTIME_TIMEOUT`, `NETWORK_TRANSPORT_RUNTIME_UNREACHABLE`, or `NETWORK_TRANSPORT_RUNTIME_UNMAPPED`. +- **Client construction bugs** (`InvalidURL`, `UnsupportedProtocol`, `MissingSchema`, `InvalidSchema`, `InvalidHeader`, `InvalidProxyURL`, `URLRequired`, `SSLError`) → `FatalToolError`. These indicate a tool-authoring mistake or local TLS configuration issue and are not retryable. + ### Explicit error adapters For tools using specific SDKs, you can specify error adapters explicitly: diff --git a/app/en/guides/tool-calling/error-handling/page.mdx b/app/en/guides/tool-calling/error-handling/page.mdx index ce5a2f65b..2faf975c2 100644 --- a/app/en/guides/tool-calling/error-handling/page.mdx +++ b/app/en/guides/tool-calling/error-handling/page.mdx @@ -60,6 +60,11 @@ def handle_tool_error(error: OutputError) -> None: elif error_kind.startswith("UPSTREAM_"): # The tool encountered an error from an upstream service print(error.message) + elif error_kind.startswith("NETWORK_TRANSPORT_"): + # The HTTP request never received a complete response (timeout, DNS + # failure, TLS handshake, etc.). These are typically transient and + # safe to retry. + print(error.message) client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable @@ -124,6 +129,11 @@ function handleToolError(error) { } else if (errorKind.startsWith("UPSTREAM_")) { // The tool encountered an error from an upstream service console.log(error.message); + } else if (errorKind.startsWith("NETWORK_TRANSPORT_")) { + // The HTTP request never received a complete response (timeout, DNS + // failure, TLS handshake, etc.). These are typically transient and + // safe to retry. + console.log(error.message); } } @@ -203,6 +213,11 @@ import org.slf4j.LoggerFactory; } else if (errorKind.asString().startsWith("UPSTREAM_")) { // The tool encountered an error from an upstream service logger.error(error.message()); + } else if (errorKind.asString().startsWith("NETWORK_TRANSPORT_")) { + // The HTTP request never received a complete response (timeout, DNS + // failure, TLS handshake, etc.). These are typically transient and + // safe to retry. + logger.error(error.message()); } } diff --git a/app/en/references/mcp/python/errors/page.mdx b/app/en/references/mcp/python/errors/page.mdx index 53dfdb05a..2020af022 100644 --- a/app/en/references/mcp/python/errors/page.mdx +++ b/app/en/references/mcp/python/errors/page.mdx @@ -145,6 +145,14 @@ Error from an upstream service the tool depends on. Rate limit error from an upstream service. +### `NetworkTransportError` + +Error raised when an HTTP request never received a complete response (e.g. connect/read timeouts, DNS failures, TLS handshake errors, decoding errors, redirect-loop exhaustion). Sibling of `UpstreamError` under `ToolExecutionError`. Unlike `UpstreamError`, `status_code` is always `None` because no response was received. Classified by `ErrorKind` into one of: + +- `NETWORK_TRANSPORT_RUNTIME_TIMEOUT` — pool, connect, or read timeouts +- `NETWORK_TRANSPORT_RUNTIME_UNREACHABLE` — DNS, connection, TLS handshake, or remote-protocol failures +- `NETWORK_TRANSPORT_RUNTIME_UNMAPPED` — decode errors, redirect exhaustion, and other transport-level fallbacks + ### `ContextRequiredToolError` Error raised when a tool requires a context that was not provided. From 7a2070f86177bffc27d6481ca4e7e00ce3de4a1b Mon Sep 17 00:00:00 2001 From: jottakka Date: Mon, 20 Apr 2026 20:38:39 -0300 Subject: [PATCH 2/3] fix(pr-920): address style suggestions and clarify FatalToolError routing - Active voice for HTTP adapter sentence (Google.Passive) - Replace e.g. with 'for example' (Google.Latin) - Remove spaces around em dashes (Google.EmDash) - Clarify FatalToolError note: caller-provided values also routed here if unvalidated Co-Authored-By: Claude Sonnet 4.6 --- .../error-handling/useful-tool-errors/page.mdx | 4 ++-- app/en/references/mcp/python/errors/page.mdx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/en/guides/create-tools/error-handling/useful-tool-errors/page.mdx b/app/en/guides/create-tools/error-handling/useful-tool-errors/page.mdx index 8384f0e4a..16c82a8e1 100644 --- a/app/en/guides/create-tools/error-handling/useful-tool-errors/page.mdx +++ b/app/en/guides/create-tools/error-handling/useful-tool-errors/page.mdx @@ -40,11 +40,11 @@ def fetch_data( return response.json() ``` -The HTTP error adapter routes exceptions from `httpx` and `requests` based on whether a complete response was received: +The HTTP error adapter routes exceptions from `httpx` and `requests` based on whether the client received a complete response: - **Real HTTP responses** (4xx/5xx) → `UpstreamError` (with `status_code`). 429 becomes `UpstreamRateLimitError`. - **No response received** (connect/read timeouts, DNS failures, connection errors, TLS handshake failures, decoding errors, redirect-loop exhaustion) → `NetworkTransportError` with `status_code=None`. Classified by `ErrorKind` as `NETWORK_TRANSPORT_RUNTIME_TIMEOUT`, `NETWORK_TRANSPORT_RUNTIME_UNREACHABLE`, or `NETWORK_TRANSPORT_RUNTIME_UNMAPPED`. -- **Client construction bugs** (`InvalidURL`, `UnsupportedProtocol`, `MissingSchema`, `InvalidSchema`, `InvalidHeader`, `InvalidProxyURL`, `URLRequired`, `SSLError`) → `FatalToolError`. These indicate a tool-authoring mistake or local TLS configuration issue and are not retryable. +- **Client construction bugs** (`InvalidURL`, `UnsupportedProtocol`, `MissingSchema`, `InvalidSchema`, `InvalidHeader`, `InvalidProxyURL`, `URLRequired`, `SSLError`) → `FatalToolError`. These are not retryable and typically indicate a tool-authoring mistake (hardcoded invalid URL, schema, or header) or a local TLS configuration issue. If your tool accepts caller-provided URLs or headers and passes them directly to the HTTP client without validation, invalid caller input is also routed here—validate caller-supplied values before use. ### Explicit error adapters diff --git a/app/en/references/mcp/python/errors/page.mdx b/app/en/references/mcp/python/errors/page.mdx index 2020af022..cd6430465 100644 --- a/app/en/references/mcp/python/errors/page.mdx +++ b/app/en/references/mcp/python/errors/page.mdx @@ -147,11 +147,11 @@ Rate limit error from an upstream service. ### `NetworkTransportError` -Error raised when an HTTP request never received a complete response (e.g. connect/read timeouts, DNS failures, TLS handshake errors, decoding errors, redirect-loop exhaustion). Sibling of `UpstreamError` under `ToolExecutionError`. Unlike `UpstreamError`, `status_code` is always `None` because no response was received. Classified by `ErrorKind` into one of: +Error raised when an HTTP request never received a complete response (for example, connect/read timeouts, DNS failures, TLS handshake errors, decoding errors, redirect-loop exhaustion). Sibling of `UpstreamError` under `ToolExecutionError`. Unlike `UpstreamError`, `status_code` is always `None` because the client received no response. Classified by `ErrorKind` into one of: -- `NETWORK_TRANSPORT_RUNTIME_TIMEOUT` — pool, connect, or read timeouts -- `NETWORK_TRANSPORT_RUNTIME_UNREACHABLE` — DNS, connection, TLS handshake, or remote-protocol failures -- `NETWORK_TRANSPORT_RUNTIME_UNMAPPED` — decode errors, redirect exhaustion, and other transport-level fallbacks +- `NETWORK_TRANSPORT_RUNTIME_TIMEOUT`—pool, connect, or read timeouts +- `NETWORK_TRANSPORT_RUNTIME_UNREACHABLE`—DNS, connection, TLS handshake, or remote-protocol failures +- `NETWORK_TRANSPORT_RUNTIME_UNMAPPED`—decode errors, redirect exhaustion, and other transport-level fallbacks ### `ContextRequiredToolError` From b6e861447439cd12ce36a1cd218a1fcd636b0827 Mon Sep 17 00:00:00 2001 From: jottakka Date: Mon, 20 Apr 2026 20:39:07 -0300 Subject: [PATCH 3/3] fix: replace em dash with period (Arcade.EmDash style) Co-Authored-By: Claude Sonnet 4.6 --- .../create-tools/error-handling/useful-tool-errors/page.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/en/guides/create-tools/error-handling/useful-tool-errors/page.mdx b/app/en/guides/create-tools/error-handling/useful-tool-errors/page.mdx index 16c82a8e1..3f433cbcb 100644 --- a/app/en/guides/create-tools/error-handling/useful-tool-errors/page.mdx +++ b/app/en/guides/create-tools/error-handling/useful-tool-errors/page.mdx @@ -44,7 +44,7 @@ The HTTP error adapter routes exceptions from `httpx` and `requests` based on wh - **Real HTTP responses** (4xx/5xx) → `UpstreamError` (with `status_code`). 429 becomes `UpstreamRateLimitError`. - **No response received** (connect/read timeouts, DNS failures, connection errors, TLS handshake failures, decoding errors, redirect-loop exhaustion) → `NetworkTransportError` with `status_code=None`. Classified by `ErrorKind` as `NETWORK_TRANSPORT_RUNTIME_TIMEOUT`, `NETWORK_TRANSPORT_RUNTIME_UNREACHABLE`, or `NETWORK_TRANSPORT_RUNTIME_UNMAPPED`. -- **Client construction bugs** (`InvalidURL`, `UnsupportedProtocol`, `MissingSchema`, `InvalidSchema`, `InvalidHeader`, `InvalidProxyURL`, `URLRequired`, `SSLError`) → `FatalToolError`. These are not retryable and typically indicate a tool-authoring mistake (hardcoded invalid URL, schema, or header) or a local TLS configuration issue. If your tool accepts caller-provided URLs or headers and passes them directly to the HTTP client without validation, invalid caller input is also routed here—validate caller-supplied values before use. +- **Client construction bugs** (`InvalidURL`, `UnsupportedProtocol`, `MissingSchema`, `InvalidSchema`, `InvalidHeader`, `InvalidProxyURL`, `URLRequired`, `SSLError`) → `FatalToolError`. These are not retryable and typically indicate a tool-authoring mistake (hardcoded invalid URL, schema, or header) or a local TLS configuration issue. If your tool accepts caller-provided URLs or headers and passes them directly to the HTTP client without validation, invalid caller input is also routed here. Validate caller-supplied values before use. ### Explicit error adapters