Repository navigation
[Bug]: v0.3 JSON-RPC compat adapter returns -32603 for all A2A errors (e.g. TaskNotFound should be -32001) #1368
Description
What happened?
With create_jsonrpc_routes(..., enable_v0_3_compat=True), A2A errors raised while handling v0.3 JSON-RPC requests are returned as -32603 Internal error instead of their A2A error codes. The v1.0 dispatcher maps them correctly.
| Request | Expected | Actual |
|---|---|---|
v1.0 GetTask, unknown id |
-32001 |
-32001 |
v0.3 tasks/get, unknown id |
-32001 |
-32603 |
v0.3 tasks/cancel, unknown id |
-32001 |
-32603 |
v0.3 message/send with unknown taskId |
-32001 |
-32603 |
v0.3 tasks/resubscribe, streaming not supported |
-32004 |
-32603 |
A v0.3 client therefore cannot distinguish "task not found" from a server failure; the SDK's own v0.3 JsonRpcTransport maps the code back to InternalError instead of TaskNotFoundError.
Cause: in src/a2a/compat/v0_3/jsonrpc_adapter.py, A2AErrors from the request handler fall through to the generic except Exception in handle_request (and in the streaming event_generator), which wraps them in InternalError. JsonRpcDispatcher handles A2AError explicitly, and the v0.3 gRPC handler maps them via _ERROR_CODE_MAP.
Reproduction (main @ 261c074, also 1.2.2):
from starlette.applications import Starlette
from starlette.testclient import TestClient
from a2a.server.agent_execution import AgentExecutor
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.routes import create_jsonrpc_routes
from a2a.server.tasks import InMemoryTaskStore
from a2a.types import AgentCapabilities, AgentCard
class NoopExecutor(AgentExecutor):
async def execute(self, context, event_queue): ...
async def cancel(self, context, event_queue): ...
card = AgentCard(name='t', description='t', version='1', capabilities=AgentCapabilities())
handler = DefaultRequestHandler(agent_executor=NoopExecutor(), task_store=InMemoryTaskStore(), agent_card=card)
app = Starlette(routes=create_jsonrpc_routes(request_handler=handler, rpc_url='/', enable_v0_3_compat=True))
client = TestClient(app)
def call(method, params, version):
body = {'jsonrpc': '2.0', 'id': '1', 'method': method, 'params': params}
return client.post('/', json=body, headers={'A2A-Version': version}).json()['error']['code']
print(call('GetTask', {'id': 'missing'}, '1.0')) # -32001
print(call('tasks/get', {'id': 'missing'}, '0.3')) # -32603, expected -32001Expected: A2A errors keep their JSON-RPC codes on the v0.3 path. Errors that only exist in v1.0 (e.g. -32009 VersionNotSupported) should stay -32603, since v0.3 clients don't know those codes.
I have a fix with tests ready and will open a PR referencing this issue.
Relevant log output
-32001
-32603Code of Conduct
- I agree to follow this project's Code of Conduct
Activity
rohityan commentedon Oct 22, 2026
Hi @shwetangsinha0509 , Thanks for the thorough report and fix. You correctly pinpointed the missing
A2AErrorhandling inJSONRPCAdapterfalling through to generic-32603errors.Your fix in PR #1369 cleanly resolves the issue while respecting the v0.3 error code spec. Assigning this issue to you till your PR gets reviewed.
shwetangsinha0509 commentedon Oct 22, 2026
Thanks @rohityan! Happy to make any changes needed on #1369.
fix(compat): return A2A error codes from the v0.3 JSON-RPC adapter (#…