A2A facade dispatch() re-raises A2aOperationNotFoundError instead of returning JSON-RPC -32601 error response #8405

Open
opened 2026-04-13 18:41:43 +00:00 by HAL9000 · 1 comment
Owner

Metadata

  • Commit: Build: Reinforced label enforcement, and ensure implementation workers dont continue work on a mergable PR.
  • Branch: main
  • SHA: 5a9aaa79edaefb1a257114f054ea87facb8efe69
  • File: src/cleveragents/a2a/facade.py

Background and Context

The A2aLocalFacade.dispatch() method is the primary entry point for all A2A operations. Its docstring explicitly states: "Returns an A2aResponse with result set on success or error set when the operation fails." However, when an unknown method is requested, the method re-raises A2aOperationNotFoundError instead of returning an A2aResponse with the JSON-RPC 2.0 standard error code -32601 (Method not found).

Per the JSON-RPC 2.0 specification (Section 5.1), method-not-found errors must be returned as structured error responses, not as Python exceptions propagating to the caller. This breaks the contract that dispatch() always returns an A2aResponse.

Current Behavior

In facade.py, the dispatch() method contains:

except A2aOperationNotFoundError:
    raise  # ← re-raises instead of returning error response
except Exception as exc:
    ...
    return A2aResponse(id=request.id, error=A2aErrorDetail(code=code, message=message))

When an unknown A2A method is called (e.g., _cleveragents/unknown/method), A2aOperationNotFoundError propagates to the caller as an unhandled exception. All other domain exceptions are correctly converted to A2aResponse with error details, but method-not-found is inconsistently re-raised.

Expected Behavior

Per JSON-RPC 2.0 spec and ADR-047, dispatch() must return:

{
  "jsonrpc": "2.0",
  "id": "<request_id>",
  "error": {
    "code": -32601,
    "message": "Method not found: _cleveragents/unknown/method"
  }
}

The dispatch() method should catch A2aOperationNotFoundError and return an A2aResponse with error=A2aErrorDetail(code=-32601, message=...) rather than re-raising.

Acceptance Criteria

  • dispatch() never raises an exception for unknown methods — always returns A2aResponse
  • Unknown method requests return A2aResponse with error.code == -32601
  • A2aOperationNotFoundError is caught and mapped to JSON-RPC error code -32601
  • Existing behaviour for all other exceptions (domain errors → error response) is preserved
  • BDD test: dispatch() with unknown method returns A2aResponse with error.code == -32601
  • BDD test: dispatch() never propagates A2aOperationNotFoundError to caller

Subtasks

  • Update dispatch() in facade.py to catch A2aOperationNotFoundError and return A2aResponse(error=A2aErrorDetail(code=-32601, message=...))
  • Remove the except A2aOperationNotFoundError: raise block
  • Add -32601 constant to errors.py error code taxonomy
  • Add BDD scenario: Given an unknown A2A method, When dispatch is called, Then an A2aResponse with error code -32601 is returned
  • Verify no callers of dispatch() catch A2aOperationNotFoundError (they should not need to)

Definition of Done

This issue is closed when dispatch() consistently returns A2aResponse for all inputs including unknown methods, with JSON-RPC 2.0 compliant error code -32601, and BDD tests cover the scenario.


Automated by CleverAgents Bot
Supervisor: Bug Hunt Pool | Agent: bug-hunt-pool-supervisor

## Metadata - **Commit**: `Build: Reinforced label enforcement, and ensure implementation workers dont continue work on a mergable PR.` - **Branch**: `main` - **SHA**: `5a9aaa79edaefb1a257114f054ea87facb8efe69` - **File**: `src/cleveragents/a2a/facade.py` ## Background and Context The `A2aLocalFacade.dispatch()` method is the primary entry point for all A2A operations. Its docstring explicitly states: *"Returns an A2aResponse with result set on success or error set when the operation fails."* However, when an unknown method is requested, the method re-raises `A2aOperationNotFoundError` instead of returning an `A2aResponse` with the JSON-RPC 2.0 standard error code `-32601` (Method not found). Per the JSON-RPC 2.0 specification (Section 5.1), method-not-found errors must be returned as structured error responses, not as Python exceptions propagating to the caller. This breaks the contract that `dispatch()` always returns an `A2aResponse`. ## Current Behavior In `facade.py`, the `dispatch()` method contains: ```python except A2aOperationNotFoundError: raise # ← re-raises instead of returning error response except Exception as exc: ... return A2aResponse(id=request.id, error=A2aErrorDetail(code=code, message=message)) ``` When an unknown A2A method is called (e.g., `_cleveragents/unknown/method`), `A2aOperationNotFoundError` propagates to the caller as an unhandled exception. All other domain exceptions are correctly converted to `A2aResponse` with error details, but method-not-found is inconsistently re-raised. ## Expected Behavior Per JSON-RPC 2.0 spec and ADR-047, `dispatch()` must return: ```json { "jsonrpc": "2.0", "id": "<request_id>", "error": { "code": -32601, "message": "Method not found: _cleveragents/unknown/method" } } ``` The `dispatch()` method should catch `A2aOperationNotFoundError` and return an `A2aResponse` with `error=A2aErrorDetail(code=-32601, message=...)` rather than re-raising. ## Acceptance Criteria - [ ] `dispatch()` never raises an exception for unknown methods — always returns `A2aResponse` - [ ] Unknown method requests return `A2aResponse` with `error.code == -32601` - [ ] `A2aOperationNotFoundError` is caught and mapped to JSON-RPC error code `-32601` - [ ] Existing behaviour for all other exceptions (domain errors → error response) is preserved - [ ] BDD test: `dispatch()` with unknown method returns `A2aResponse` with `error.code == -32601` - [ ] BDD test: `dispatch()` never propagates `A2aOperationNotFoundError` to caller ## Subtasks - [ ] Update `dispatch()` in `facade.py` to catch `A2aOperationNotFoundError` and return `A2aResponse(error=A2aErrorDetail(code=-32601, message=...))` - [ ] Remove the `except A2aOperationNotFoundError: raise` block - [ ] Add `-32601` constant to `errors.py` error code taxonomy - [ ] Add BDD scenario: `Given an unknown A2A method, When dispatch is called, Then an A2aResponse with error code -32601 is returned` - [ ] Verify no callers of `dispatch()` catch `A2aOperationNotFoundError` (they should not need to) ## Definition of Done This issue is closed when `dispatch()` consistently returns `A2aResponse` for all inputs including unknown methods, with JSON-RPC 2.0 compliant error code `-32601`, and BDD tests cover the scenario. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunt Pool | Agent: bug-hunt-pool-supervisor
HAL9000 added this to the v3.5.0 milestone 2026-04-13 18:51:03 +00:00
Author
Owner

Verified — Raising an exception instead of returning a JSON-RPC -32601 error response breaks the A2A protocol contract. MoSCoW: Must Have for v3.5.0 — protocol compliance is non-negotiable. [AUTO-OWNR-1]


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: project-owner-pool-supervisor

✅ **Verified** — Raising an exception instead of returning a JSON-RPC -32601 error response breaks the A2A protocol contract. **MoSCoW: Must Have** for v3.5.0 — protocol compliance is non-negotiable. [AUTO-OWNR-1] --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#8405
No description provided.