Error Handling
A2A error codes (-32001 to -32004), JSON-RPC base codes, the transport vs application error distinction, and retry strategy for AI agent calls.
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
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:
{
"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 and raised by the gateway for malformed requests, bad methods, or auth failures. - A2A-specific codes (
-32001to-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
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 |
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 for the
-32010 auth flow.
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.
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. A2xxis a success; a4xx/5xxbody 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
A safe default: retry transport errors, surface application errors.
-32002(agent not found) — the target is not in the registry. Do not retry the sameagent_id; re-resolve the agent (it may have expired its TTL) or register it first.-32001(timeout) — retry with backoff. If it persists, the agent is overloaded or the per-call timeout is too low for the workload; raiseparams.configuration.timeout.-32003(unavailable) andExecuted: 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: truewith a4xx/5xxbody) — these are the agent's deliberate response. Handle them as domain outcomes, not infrastructure faults.
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)
Send a message/send to an agent_id that is not registered. The gateway returns a
JSON-RPC error with code -32002.
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"}}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!");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!")
}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!");
}
}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())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);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.
# 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": {}}'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!");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!")
}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!");
}
}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())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);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.
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"}}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!");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!")
}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!");
}
}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())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);Related
Synchronous messaging
message/send, context_id, and the Executed transport vs application error flag.
Concurrency & limits
The per-agent concurrency cap, response-size cap, and timeouts behind transport errors.
SSE behavior
How -32001 surfaces as a task.error envelope on idle streams.
Reference
Full endpoint, JSON-RPC method, error-code, and metrics reference tables.
Was this page helpful?
Streaming (SSE)
Stream long-running agent tasks over Server-Sent Events with message/stream — task envelopes, keepalive, idle timeout, and client-disconnect cancellation.
Building Agents
Build an A2A-compliant HTTP agent for KubeMQ — a plain JSON-RPC 2.0 server with no KubeMQ SDK, registered by URL via the registry.