# Error Handling (/aiway/a2a/error-handling)



Every A2A response is a **JSON-RPC 2.0** envelope, so failures come back as a structured
`error` object with a numeric `code` and a `message` — never as a raw HTTP error. This
page is the field guide to those codes: which ones the gateway raises, which come from
the agent, and how to decide whether to retry.

## Overview [#overview]

The A2A gateway returns errors at HTTP `200` with a JSON-RPC `error` body for anything it
can parse as a request. A failed call looks like this:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32002,
    "message": "agent not found: nonexistent-agent"
  }
}
```

There are two families of codes:

* **JSON-RPC base codes** (`-32700`, `-32600`, `-32601`, `-32602`, `-32603`, `-32010`)
  — shared with the [MCP connector](/aiway/mcp) and raised by the gateway for
  malformed requests, bad methods, or auth failures.
* **A2A-specific codes** (`-32001` to `-32004`) — raised when the gateway routes to a
  registered agent but the call to that agent fails (timeout, missing agent, rejection,
  or an unparseable reply).

## JSON-RPC base codes [#json-rpc-base-codes]

These are the standard JSON-RPC 2.0 codes returned by the shared HTTP layer for requests
that never reach an agent — the body or method is wrong, or authentication failed.

| Code     | Constant                | Meaning                | Typical cause                                                              |
| -------- | ----------------------- | ---------------------- | -------------------------------------------------------------------------- |
| `-32700` | `JSONRPCParseError`     | Parse error            | Invalid JSON body, or `Content-Type` is not `application/json`             |
| `-32600` | `JSONRPCInvalidRequest` | Invalid request        | Missing `method`, wrong `jsonrpc` version, or an invalid `agent_id` format |
| `-32601` | `JSONRPCMethodNotFound` | Method not found       | Unknown `method` for the endpoint                                          |
| `-32602` | `JSONRPCInvalidParams`  | Invalid params         | The `params` object failed validation                                      |
| `-32603` | `JSONRPCInternalError`  | Internal error         | Unexpected gateway-side failure                                            |
| `-32010` | `jsonrpcAuthError`      | Authentication failure | Missing or invalid JWT on a protected route                                |

<Callout type="info">
  The `agent_id` in the URL path is validated before routing. An invalid format (for
  example uppercase characters) is rejected with `-32600` — the request never reaches an
  agent. See [Authentication](/aiway/a2a/guides/authentication) for the
  `-32010` auth flow.
</Callout>

## A2A-specific codes [#a2a-specific-codes]

These codes are raised by the gateway when it has a registered agent to route to but the
outbound HTTP call to that agent fails.

| Code     | Constant                  | Meaning                                                        |
| -------- | ------------------------- | -------------------------------------------------------------- |
| `-32001` | `jsonrpcAgentTimeout`     | The agent did not respond within the request timeout           |
| `-32002` | `jsonrpcAgentNotFound`    | No agent is registered under that `agent_id`                   |
| `-32003` | `jsonrpcAgentUnavailable` | The agent rejected the request (unreachable or returned a 5xx) |
| `-32004` | `jsonrpcInvalidResponse`  | The agent replied, but the body was not valid JSON-RPC         |

The request timeout that drives `-32001` defaults to `DefaultTimeoutSeconds` (300s) and is
capped by `MaxTimeoutSeconds` (3600s); per-call, set `params.configuration.timeout`
(seconds) to lower it. The same code is also emitted as a `task.error` envelope when an
SSE stream hits its idle timeout (`MaxSSEIdleSeconds`, default 300s) — see
[SSE behavior](/aiway/a2a/guides/sse-behavior).

## Transport vs application errors [#transport-vs-application-errors]

Underneath the JSON-RPC codes, the gateway's virtual subscriber draws a sharp line
between a call the agent **never processed** and one it **processed but rejected**. This
distinction is what lets you decide whether retrying is safe.

The agent's reply carries an `Executed` flag:

* **`Executed: false`** — a **transport error**. The agent never handled the request, so
  retrying (against another instance, or after a backoff) is safe. Mapped to `-32001`
  (timeout), `-32002` (not found), or `-32003` (unavailable).
* **`Executed: true`** — the agent **did** process the request. A `2xx` is a success; a
  `4xx`/`5xx` body is an **application error** the agent chose to return. Retrying the
  same call will produce the same result, so handle it as a business outcome rather than
  blindly retrying.

| Condition                                              | Gateway result                                               | Classification |
| ------------------------------------------------------ | ------------------------------------------------------------ | -------------- |
| Connection refused / DNS failure                       | `Executed: false` · "agent unreachable"                      | Transport      |
| HTTP timeout (deadline exceeded)                       | `Executed: false` · "agent timeout"                          | Transport      |
| HTTP 502 / 503 / 504                                   | `Executed: false` · "agent unavailable: 50x"                 | Transport      |
| Response body exceeds `AgentMaxResponseBytes` (10 MB)  | `Executed: false` · "agent response too large"               | Transport      |
| Concurrency limit reached (`AgentMaxConcurrency`, 100) | `Executed: false` · "server busy: concurrency limit reached" | Transport      |
| HTTP 200–299                                           | `Executed: true` · response body                             | Success        |
| HTTP 400 / 401 / 403 / 404 / 409 / 422 / 500           | `Executed: true` · response body                             | Application    |

## Retry strategy [#retry-strategy]

A safe default: &#x2A;*retry transport errors, surface application errors.**

* **`-32002` (agent not found)** — the target is not in the registry. Do not retry the
  same `agent_id`; re-resolve the agent (it may have expired its TTL) or
  [register it](/aiway/a2a/registry) first.
* **`-32001` (timeout)** — retry with backoff. If it persists, the agent is overloaded or
  the per-call timeout is too low for the workload; raise
  `params.configuration.timeout`.
* **`-32003` (unavailable)** and `Executed: false` — the agent never ran the request;
  retry with exponential backoff, optionally against a healthy instance.
* **`-32004` (invalid response)** — the agent is misbehaving (non-JSON-RPC body). Retrying
  rarely helps; treat it as a bug in the agent.
* **JSON-RPC base codes** (`-32600`, `-32602`, `-32700`) — the request itself is wrong.
  Fix the payload; retrying unchanged will fail identically.
* **Application errors** (`Executed: true` with a `4xx`/`5xx` body) — these are the
  agent's deliberate response. Handle them as domain outcomes, not infrastructure faults.

## Examples [#examples]

The snippets below trigger each error family against a running gateway: a missing agent
(`-32002`), malformed JSON-RPC requests (base codes), and a timeout (`-32001`).

### Agent not found (-32002) [#agent-not-found--32002]

Send a `message/send` to an `agent_id` that is not registered. The gateway returns a
JSON-RPC error with code `-32002`.

<Tabs groupId="language" items="['curl','C#','Go','Java','Python','TypeScript']">
  <Tab value="curl">
    ```bash
    curl -X POST http://localhost:9090/a2a/nonexistent-agent \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "id": 1,
        "method": "message/send",
        "params": {"message": {"parts": [{"text": "Hello?"}]}}
      }'
    # => {"jsonrpc":"2.0","id":1,"error":{"code":-32002,"message":"agent not found: nonexistent-agent"}}
    ```
  </Tab>

  <Tab value="C#">
    ```csharp
    using System.Text;
    using System.Text.Json;
    using System.Text.Json.Nodes;

    const string KubeMqUrl = "http://localhost:9090";
    const string AgentId = "nonexistent-agent";

    var payload = new JsonObject
    {
        ["jsonrpc"] = "2.0",
        ["id"] = 1,
        ["method"] = "message/send",
        ["params"] = new JsonObject
        {
            ["message"] = new JsonObject
            {
                ["parts"] = new JsonArray(new JsonObject { ["text"] = "Hello?" })
            }
        }
    };

    using var client = new HttpClient();
    var resp = await client.PostAsync(
        $"{KubeMqUrl}/a2a/{AgentId}",
        new StringContent(payload.ToJsonString(), Encoding.UTF8, "application/json"));

    var body = await resp.Content.ReadAsStringAsync();
    var data = JsonNode.Parse(body)!;
    Console.WriteLine(JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true }));

    var error = data["error"];
    Console.WriteLine($"\nError code:    {error?["code"]}");
    Console.WriteLine($"Error message: {error?["message"]}");

    var code = error?["code"]?.GetValue<int>();
    if (code == -32002)
        Console.WriteLine("\nAgent-not-found error (-32002) received as expected!");
    ```
  </Tab>

  <Tab value="Go">
    ```go
    package main

    import (
    	"bytes"
    	"encoding/json"
    	"fmt"
    	"io"
    	"net/http"
    	"os"
    )

    const (
    	kubemqURL = "http://localhost:9090"
    	agentID   = "nonexistent-agent"
    )

    func main() {
    	payload := map[string]interface{}{
    		"jsonrpc": "2.0",
    		"id":      1,
    		"method":  "message/send",
    		"params": map[string]interface{}{
    			"message": map[string]interface{}{
    				"parts": []map[string]interface{}{{"text": "Hello?"}},
    			},
    		},
    	}

    	data, _ := json.Marshal(payload)
    	resp, err := http.Post(kubemqURL+"/a2a/"+agentID, "application/json", bytes.NewReader(data))
    	if err != nil {
    		fmt.Fprintf(os.Stderr, "Request failed: %v\n", err)
    		os.Exit(1)
    	}
    	defer resp.Body.Close()

    	body, _ := io.ReadAll(resp.Body)
    	var pretty bytes.Buffer
    	json.Indent(&pretty, body, "", "  ")
    	fmt.Println(pretty.String())

    	var result map[string]interface{}
    	json.Unmarshal(body, &result)

    	errorObj, _ := result["error"].(map[string]interface{})
    	code, _ := errorObj["code"].(float64)
    	msg, _ := errorObj["message"].(string)
    	fmt.Printf("\nError code:    %.0f\n", code)
    	fmt.Printf("Error message: %s\n", msg)

    	if int(code) != -32002 {
    		fmt.Fprintf(os.Stderr, "Expected -32002, got %.0f\n", code)
    		os.Exit(1)
    	}
    	fmt.Println("\nAgent-not-found error (-32002) received as expected!")
    }
    ```
  </Tab>

  <Tab value="Java">
    ```java
    import com.fasterxml.jackson.databind.ObjectMapper;

    import java.net.URI;
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    import java.util.List;
    import java.util.Map;

    public class Client {

        static final String KUBEMQ_URL = "http://localhost:9090";
        static final String AGENT_ID = "nonexistent-agent";
        static final ObjectMapper MAPPER = new ObjectMapper();

        public static void main(String[] args) throws Exception {
            var payload = Map.of(
                "jsonrpc", "2.0",
                "id", 1,
                "method", "message/send",
                "params", Map.of(
                    "message", Map.of("parts", List.of(Map.of("text", "Hello?")))
                )
            );

            var client = HttpClient.newHttpClient();
            var req = HttpRequest.newBuilder()
                .uri(URI.create(KUBEMQ_URL + "/a2a/" + AGENT_ID))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(MAPPER.writeValueAsString(payload)))
                .build();
            var resp = client.send(req, HttpResponse.BodyHandlers.ofString());
            var data = MAPPER.readTree(resp.body());
            System.out.println(MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(data));

            var error = data.path("error");
            System.out.println("\nError code:    " + error.path("code").asInt());
            System.out.println("Error message: " + error.path("message").asText());

            assert error.path("code").asInt() == -32002 : "Expected -32002, got " + error.path("code").asInt();
            System.out.println("\nAgent-not-found error (-32002) received as expected!");
        }
    }
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import asyncio
    import json

    import httpx

    KUBEMQ_URL = "http://localhost:9090"
    AGENT_ID = "nonexistent-agent"


    async def main() -> None:
        payload = {
            "jsonrpc": "2.0",
            "id": 1,
            "method": "message/send",
            "params": {
                "message": {"parts": [{"text": "Hello?"}]},
            },
        }

        async with httpx.AsyncClient() as client:
            resp = await client.post(f"{KUBEMQ_URL}/a2a/{AGENT_ID}", json=payload)
            data = resp.json()
            print(json.dumps(data, indent=2))

            error = data.get("error", {})
            print(f"\nError code:    {error.get('code')}")
            print(f"Error message: {error.get('message')}")

            assert error.get("code") == -32002, f"Expected -32002, got {error.get('code')}"
            print("\nAgent-not-found error (-32002) received as expected!")


    if __name__ == "__main__":
        asyncio.run(main())
    ```
  </Tab>

  <Tab value="TypeScript">
    ```typescript
    const KUBEMQ_URL = "http://localhost:9090";

    async function main() {
      const request = {
        jsonrpc: "2.0",
        id: 1,
        method: "message/send",
        params: {
          message: { parts: [{ text: "Hello?" }] },
        },
      };

      console.log("Sending to nonexistent agent...");

      const resp = await fetch(`${KUBEMQ_URL}/a2a/nonexistent-agent`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(request),
      });

      const data = await resp.json();
      console.log("Response:", JSON.stringify(data, null, 2));

      if (data.error) {
        console.log(`\nError code:    ${data.error.code} (expect -32002)`);
        console.log(`Error message: ${data.error.message}`);
        console.log(`Match:         ${data.error.code === -32002}`);
      }
    }

    main().catch(console.error);
    ```
  </Tab>
</Tabs>

### Invalid request (JSON-RPC base codes) [#invalid-request-json-rpc-base-codes]

Malformed payloads are rejected by the gateway with base codes — invalid JSON or a wrong
`Content-Type` yields `-32700`, while a missing `method` or wrong `jsonrpc` version yields
`-32600`.

<Tabs groupId="language" items="['curl','C#','Go','Java','Python','TypeScript']">
  <Tab value="curl">
    ```bash
    # Invalid JSON body -> -32700
    curl -X POST http://localhost:9090/a2a/echo-agent-01 \
      -H "Content-Type: application/json" \
      -d '{invalid json!!!}'

    # Missing method field -> -32600
    curl -X POST http://localhost:9090/a2a/echo-agent-01 \
      -H "Content-Type: application/json" \
      -d '{"jsonrpc": "2.0", "id": 1, "params": {}}'

    # Bad jsonrpc version -> -32600
    curl -X POST http://localhost:9090/a2a/echo-agent-01 \
      -H "Content-Type: application/json" \
      -d '{"jsonrpc": "1.0", "id": 1, "method": "message/send", "params": {}}'
    ```
  </Tab>

  <Tab value="C#">
    ```csharp
    using System.Text;
    using System.Text.Json.Nodes;

    const string KubeMqUrl = "http://localhost:9090";
    const string AgentId = "echo-agent-01";

    using var client = new HttpClient();

    Console.WriteLine("=== Test 1: Invalid JSON ===");
    var resp = await client.PostAsync(
        $"{KubeMqUrl}/a2a/{AgentId}",
        new StringContent("{invalid json!!!}", Encoding.UTF8, "application/json"));
    var data = JsonNode.Parse(await resp.Content.ReadAsStringAsync())!;
    var error = data["error"];
    Console.WriteLine($"  Code: {error?["code"]} (expected -32700)");
    Console.WriteLine($"  Message: {error?["message"]}");

    Console.WriteLine("\n=== Test 2: Missing method field ===");
    var payload2 = new JsonObject
    {
        ["jsonrpc"] = "2.0",
        ["id"] = 1,
        ["params"] = new JsonObject()
    };
    resp = await client.PostAsync(
        $"{KubeMqUrl}/a2a/{AgentId}",
        new StringContent(payload2.ToJsonString(), Encoding.UTF8, "application/json"));
    data = JsonNode.Parse(await resp.Content.ReadAsStringAsync())!;
    error = data["error"];
    Console.WriteLine($"  Code: {error?["code"]} (expected -32600)");
    Console.WriteLine($"  Message: {error?["message"]}");

    Console.WriteLine("\n=== Test 3: Bad jsonrpc version ===");
    var payload3 = new JsonObject
    {
        ["jsonrpc"] = "1.0",
        ["id"] = 1,
        ["method"] = "message/send",
        ["params"] = new JsonObject()
    };
    resp = await client.PostAsync(
        $"{KubeMqUrl}/a2a/{AgentId}",
        new StringContent(payload3.ToJsonString(), Encoding.UTF8, "application/json"));
    data = JsonNode.Parse(await resp.Content.ReadAsStringAsync())!;
    error = data["error"];
    Console.WriteLine($"  Code: {error?["code"]} (expected -32600)");
    Console.WriteLine($"  Message: {error?["message"]}");

    Console.WriteLine("\nAll invalid request errors demonstrated!");
    ```
  </Tab>

  <Tab value="Go">
    ```go
    package main

    import (
    	"bytes"
    	"encoding/json"
    	"fmt"
    	"io"
    	"net/http"
    	"os"
    	"strings"
    )

    const (
    	kubemqURL = "http://localhost:9090"
    	agentID   = "echo-agent-01"
    )

    func main() {
    	fmt.Println("=== Test 1: Invalid JSON ===")
    	req, _ := http.NewRequest("POST", kubemqURL+"/a2a/"+agentID, strings.NewReader("{invalid json!!!}"))
    	req.Header.Set("Content-Type", "application/json")
    	resp, err := http.DefaultClient.Do(req)
    	if err != nil {
    		fmt.Fprintf(os.Stderr, "Request failed: %v\n", err)
    		os.Exit(1)
    	}
    	body, _ := io.ReadAll(resp.Body)
    	resp.Body.Close()
    	var data map[string]interface{}
    	json.Unmarshal(body, &data)
    	errorObj, _ := data["error"].(map[string]interface{})
    	code, _ := errorObj["code"].(float64)
    	fmt.Printf("  Code: %.0f (expected -32700)\n", code)
    	fmt.Printf("  Message: %v\n", errorObj["message"])

    	fmt.Println("\n=== Test 2: Missing method field ===")
    	payload2, _ := json.Marshal(map[string]interface{}{
    		"jsonrpc": "2.0",
    		"id":      1,
    		"params":  map[string]interface{}{},
    	})
    	resp, _ = http.Post(kubemqURL+"/a2a/"+agentID, "application/json", bytes.NewReader(payload2))
    	body, _ = io.ReadAll(resp.Body)
    	resp.Body.Close()
    	json.Unmarshal(body, &data)
    	errorObj, _ = data["error"].(map[string]interface{})
    	code, _ = errorObj["code"].(float64)
    	fmt.Printf("  Code: %.0f (expected -32600)\n", code)
    	fmt.Printf("  Message: %v\n", errorObj["message"])

    	fmt.Println("\n=== Test 3: Bad jsonrpc version ===")
    	payload3, _ := json.Marshal(map[string]interface{}{
    		"jsonrpc": "1.0",
    		"id":      1,
    		"method":  "message/send",
    		"params":  map[string]interface{}{},
    	})
    	resp, _ = http.Post(kubemqURL+"/a2a/"+agentID, "application/json", bytes.NewReader(payload3))
    	body, _ = io.ReadAll(resp.Body)
    	resp.Body.Close()
    	json.Unmarshal(body, &data)
    	errorObj, _ = data["error"].(map[string]interface{})
    	code, _ = errorObj["code"].(float64)
    	fmt.Printf("  Code: %.0f (expected -32600)\n", code)
    	fmt.Printf("  Message: %v\n", errorObj["message"])

    	fmt.Println("\nAll invalid request errors demonstrated!")
    }
    ```
  </Tab>

  <Tab value="Java">
    ```java
    import com.fasterxml.jackson.databind.ObjectMapper;

    import java.net.URI;
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    import java.util.Map;

    public class Client {

        static final String KUBEMQ_URL = "http://localhost:9090";
        static final String AGENT_ID = "echo-agent-01";
        static final ObjectMapper MAPPER = new ObjectMapper();

        public static void main(String[] args) throws Exception {
            var client = HttpClient.newHttpClient();

            System.out.println("=== Test 1: Invalid JSON ===");
            var req = HttpRequest.newBuilder()
                .uri(URI.create(KUBEMQ_URL + "/a2a/" + AGENT_ID))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString("{invalid json!!!}"))
                .build();
            var resp = client.send(req, HttpResponse.BodyHandlers.ofString());
            var data = MAPPER.readTree(resp.body());
            var error = data.path("error");
            System.out.println("  Code: " + error.path("code").asInt() + " (expected -32700)");
            System.out.println("  Message: " + error.path("message").asText());

            System.out.println("\n=== Test 2: Missing method field ===");
            req = HttpRequest.newBuilder()
                .uri(URI.create(KUBEMQ_URL + "/a2a/" + AGENT_ID))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(
                    MAPPER.writeValueAsString(Map.of("jsonrpc", "2.0", "id", 1, "params", Map.of()))))
                .build();
            resp = client.send(req, HttpResponse.BodyHandlers.ofString());
            data = MAPPER.readTree(resp.body());
            error = data.path("error");
            System.out.println("  Code: " + error.path("code").asInt() + " (expected -32600)");
            System.out.println("  Message: " + error.path("message").asText());

            System.out.println("\n=== Test 3: Bad jsonrpc version ===");
            req = HttpRequest.newBuilder()
                .uri(URI.create(KUBEMQ_URL + "/a2a/" + AGENT_ID))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(
                    MAPPER.writeValueAsString(Map.of(
                        "jsonrpc", "1.0", "id", 1, "method", "message/send", "params", Map.of()))))
                .build();
            resp = client.send(req, HttpResponse.BodyHandlers.ofString());
            data = MAPPER.readTree(resp.body());
            error = data.path("error");
            System.out.println("  Code: " + error.path("code").asInt() + " (expected -32600)");
            System.out.println("  Message: " + error.path("message").asText());

            System.out.println("\nAll invalid request errors demonstrated!");
        }
    }
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import asyncio

    import httpx

    KUBEMQ_URL = "http://localhost:9090"
    AGENT_ID = "echo-agent-01"


    async def main() -> None:
        async with httpx.AsyncClient() as client:
            print("=== Test 1: Invalid JSON ===")
            resp = await client.post(
                f"{KUBEMQ_URL}/a2a/{AGENT_ID}",
                content=b"{invalid json!!!}",
                headers={"Content-Type": "application/json"},
            )
            data = resp.json()
            error = data.get("error", {})
            print(f"  Code: {error.get('code')} (expected -32700)")
            print(f"  Message: {error.get('message')}")

            print("\n=== Test 2: Missing method field ===")
            resp = await client.post(
                f"{KUBEMQ_URL}/a2a/{AGENT_ID}",
                json={"jsonrpc": "2.0", "id": 1, "params": {}},
            )
            data = resp.json()
            error = data.get("error", {})
            print(f"  Code: {error.get('code')} (expected -32600)")
            print(f"  Message: {error.get('message')}")

            print("\n=== Test 3: Bad jsonrpc version ===")
            resp = await client.post(
                f"{KUBEMQ_URL}/a2a/{AGENT_ID}",
                json={"jsonrpc": "1.0", "id": 1, "method": "message/send", "params": {}},
            )
            data = resp.json()
            error = data.get("error", {})
            print(f"  Code: {error.get('code')} (expected -32600)")
            print(f"  Message: {error.get('message')}")

            print("\nAll invalid request errors demonstrated!")


    if __name__ == "__main__":
        asyncio.run(main())
    ```
  </Tab>

  <Tab value="TypeScript">
    ```typescript
    const KUBEMQ_URL = "http://localhost:9090";
    const AGENT_ID = "echo-agent-01";

    async function sendRaw(label: string, url: string, opts: RequestInit) {
      console.log(`=== ${label} ===`);
      try {
        const resp = await fetch(url, opts);
        const text = await resp.text();
        let data: unknown;
        try {
          data = JSON.parse(text);
        } catch {
          data = text;
        }
        console.log(`Status: ${resp.status}`);
        console.log(`Response: ${JSON.stringify(data, null, 2)}\n`);
      } catch (err) {
        console.log(`Error: ${err}\n`);
      }
    }

    async function main() {
      await sendRaw(
        "Invalid JSON body (expect -32700)",
        `${KUBEMQ_URL}/a2a/${AGENT_ID}`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: "{invalid json!!!}",
        },
      );

      await sendRaw(
        "Missing method field (expect -32600)",
        `${KUBEMQ_URL}/a2a/${AGENT_ID}`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ jsonrpc: "2.0", id: 1, params: {} }),
        },
      );

      await sendRaw(
        "Wrong JSON-RPC version (expect -32600)",
        `${KUBEMQ_URL}/a2a/${AGENT_ID}`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ jsonrpc: "1.0", id: 1, method: "message/send", params: {} }),
        },
      );

      await sendRaw(
        "Wrong Content-Type (expect -32700)",
        `${KUBEMQ_URL}/a2a/${AGENT_ID}`,
        {
          method: "POST",
          headers: { "Content-Type": "text/plain" },
          body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "message/send", params: {} }),
        },
      );

      await sendRaw(
        "Invalid agent_id format (expect -32600)",
        `${KUBEMQ_URL}/a2a/UPPERCASE-BAD`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "message/send", params: {} }),
        },
      );
    }

    main().catch(console.error);
    ```
  </Tab>
</Tabs>

### Timeout (-32001) [#timeout--32001]

Set a short per-call timeout via `params.configuration.timeout` (seconds) and target an
agent that is slower than that. The gateway returns `-32001` once the deadline passes.

<Tabs groupId="language" items="['curl','C#','Go','Java','Python','TypeScript']">
  <Tab value="curl">
    ```bash
    curl -X POST http://localhost:9090/a2a/slow-agent-01 \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "id": 1,
        "method": "message/send",
        "params": {
          "message": {"parts": [{"text": "This will timeout"}]},
          "configuration": {"timeout": 1}
        }
      }'
    # => {"jsonrpc":"2.0","id":1,"error":{"code":-32001,"message":"agent timeout: slow-agent-01"}}
    ```
  </Tab>

  <Tab value="C#">
    ```csharp
    using System.Text;
    using System.Text.Json;
    using System.Text.Json.Nodes;

    const string KubeMqUrl = "http://localhost:9090";
    const string AgentId = "slow-agent-01";

    var payload = new JsonObject
    {
        ["jsonrpc"] = "2.0",
        ["id"] = 1,
        ["method"] = "message/send",
        ["params"] = new JsonObject
        {
            ["message"] = new JsonObject
            {
                ["parts"] = new JsonArray(new JsonObject { ["text"] = "This will timeout" })
            },
            ["configuration"] = new JsonObject { ["timeout"] = 1 }
        }
    };

    using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
    Console.WriteLine("Sending request with timeout=1 to slow agent (5s delay)...");

    var resp = await client.PostAsync(
        $"{KubeMqUrl}/a2a/{AgentId}",
        new StringContent(payload.ToJsonString(), Encoding.UTF8, "application/json"));

    var body = await resp.Content.ReadAsStringAsync();
    var data = JsonNode.Parse(body)!;
    Console.WriteLine(JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true }));

    var error = data["error"];
    Console.WriteLine($"\nError code:    {error?["code"]}");
    Console.WriteLine($"Error message: {error?["message"]}");

    var code = error?["code"]?.GetValue<int>();
    if (code == -32001)
        Console.WriteLine("\nTimeout error (-32001) received as expected!");
    ```
  </Tab>

  <Tab value="Go">
    ```go
    package main

    import (
    	"bytes"
    	"encoding/json"
    	"fmt"
    	"io"
    	"net/http"
    	"os"
    	"time"
    )

    const (
    	kubemqURL = "http://localhost:9090"
    	agentID   = "slow-agent-01"
    )

    func main() {
    	payload := map[string]interface{}{
    		"jsonrpc": "2.0",
    		"id":      1,
    		"method":  "message/send",
    		"params": map[string]interface{}{
    			"message":       map[string]interface{}{"parts": []map[string]interface{}{{"text": "This will timeout"}}},
    			"configuration": map[string]interface{}{"timeout": 1},
    		},
    	}

    	data, _ := json.Marshal(payload)
    	fmt.Println("Sending request with timeout=1 to slow agent (5s delay)...")

    	client := &http.Client{Timeout: 30 * time.Second}
    	resp, err := client.Post(kubemqURL+"/a2a/"+agentID, "application/json", bytes.NewReader(data))
    	if err != nil {
    		fmt.Fprintf(os.Stderr, "Request failed: %v\n", err)
    		os.Exit(1)
    	}
    	defer resp.Body.Close()

    	body, _ := io.ReadAll(resp.Body)
    	var pretty bytes.Buffer
    	json.Indent(&pretty, body, "", "  ")
    	fmt.Println(pretty.String())

    	var result map[string]interface{}
    	json.Unmarshal(body, &result)

    	errorObj, _ := result["error"].(map[string]interface{})
    	code, _ := errorObj["code"].(float64)
    	msg, _ := errorObj["message"].(string)
    	fmt.Printf("\nError code:    %.0f\n", code)
    	fmt.Printf("Error message: %s\n", msg)

    	if int(code) != -32001 {
    		fmt.Fprintf(os.Stderr, "Expected -32001, got %.0f\n", code)
    		os.Exit(1)
    	}
    	fmt.Println("\nTimeout error (-32001) received as expected!")
    }
    ```
  </Tab>

  <Tab value="Java">
    ```java
    import com.fasterxml.jackson.databind.ObjectMapper;

    import java.net.URI;
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    import java.time.Duration;
    import java.util.List;
    import java.util.Map;

    public class Client {

        static final String KUBEMQ_URL = "http://localhost:9090";
        static final String AGENT_ID = "slow-agent-01";
        static final ObjectMapper MAPPER = new ObjectMapper();

        public static void main(String[] args) throws Exception {
            var payload = Map.of(
                "jsonrpc", "2.0",
                "id", 1,
                "method", "message/send",
                "params", Map.of(
                    "message", Map.of("parts", List.of(Map.of("text", "This will timeout"))),
                    "configuration", Map.of("timeout", 1)
                )
            );

            var client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();
            var req = HttpRequest.newBuilder()
                .uri(URI.create(KUBEMQ_URL + "/a2a/" + AGENT_ID))
                .header("Content-Type", "application/json")
                .timeout(Duration.ofSeconds(30))
                .POST(HttpRequest.BodyPublishers.ofString(MAPPER.writeValueAsString(payload)))
                .build();

            System.out.println("Sending request with timeout=1 to slow agent (5s delay)...");
            var resp = client.send(req, HttpResponse.BodyHandlers.ofString());
            var data = MAPPER.readTree(resp.body());
            System.out.println(MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(data));

            var error = data.path("error");
            System.out.println("\nError code:    " + error.path("code").asInt());
            System.out.println("Error message: " + error.path("message").asText());

            assert error.path("code").asInt() == -32001 : "Expected -32001, got " + error.path("code").asInt();
            System.out.println("\nTimeout error (-32001) received as expected!");
        }
    }
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import asyncio
    import json

    import httpx

    KUBEMQ_URL = "http://localhost:9090"
    AGENT_ID = "slow-agent-01"


    async def main() -> None:
        payload = {
            "jsonrpc": "2.0",
            "id": 1,
            "method": "message/send",
            "params": {
                "message": {"parts": [{"text": "This will timeout"}]},
                "configuration": {"timeout": 1},
            },
        }

        async with httpx.AsyncClient(timeout=30) as client:
            print("Sending request with timeout=1 to slow agent (5s delay)...")
            resp = await client.post(f"{KUBEMQ_URL}/a2a/{AGENT_ID}", json=payload)
            data = resp.json()
            print(json.dumps(data, indent=2))

            error = data.get("error", {})
            print(f"\nError code:    {error.get('code')}")
            print(f"Error message: {error.get('message')}")

            assert error.get("code") == -32001, f"Expected -32001, got {error.get('code')}"
            print("\nTimeout error (-32001) received as expected!")


    if __name__ == "__main__":
        asyncio.run(main())
    ```
  </Tab>

  <Tab value="TypeScript">
    ```typescript
    const KUBEMQ_URL = "http://localhost:9090";
    const AGENT_ID = "slow-agent-01";

    async function main() {
      const request = {
        jsonrpc: "2.0",
        id: 1,
        method: "message/send",
        params: {
          message: { parts: [{ text: "This will timeout" }] },
          configuration: { timeout: 1 },
        },
      };

      console.log("Sending with timeout=1s to a 5s-delay agent...");

      const resp = await fetch(`${KUBEMQ_URL}/a2a/${AGENT_ID}`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(request),
      });

      const data = await resp.json();
      console.log("Response:", JSON.stringify(data, null, 2));

      if (data.error) {
        console.log(`\nError code:    ${data.error.code} (expect -32001)`);
        console.log(`Error message: ${data.error.message}`);
        console.log(`Match:         ${data.error.code === -32001}`);
      } else {
        console.log("\nUnexpected: got success response instead of timeout");
      }
    }

    main().catch(console.error);
    ```
  </Tab>
</Tabs>

## Related [#related]

<Cards>
  <Card title="Synchronous messaging" href="/aiway/a2a/sync-messaging" description="message/send, context_id, and the Executed transport vs application error flag." />

  <Card title="Concurrency & limits" href="/aiway/a2a/guides/concurrency" description="The per-agent concurrency cap, response-size cap, and timeouts behind transport errors." />

  <Card title="SSE behavior" href="/aiway/a2a/guides/sse-behavior" description="How -32001 surfaces as a task.error envelope on idle streams." />

  <Card title="Reference" href="/aiway/a2a/reference" description="Full endpoint, JSON-RPC method, error-code, and metrics reference tables." />
</Cards>
