From 08cdcdf8b341158e53994b4f21413230702bfd88 Mon Sep 17 00:00:00 2001 From: Nathan Brake <33383515+njbrake@users.noreply.github.com> Date: Tue, 1 Jul 2025 13:34:55 -0400 Subject: [PATCH 1/3] fix: client should not specify taskId if it doesn't exist --- src/a2a/server/request_handlers/default_request_handler.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/a2a/server/request_handlers/default_request_handler.py b/src/a2a/server/request_handlers/default_request_handler.py index f3b584d4..3f32d700 100644 --- a/src/a2a/server/request_handlers/default_request_handler.py +++ b/src/a2a/server/request_handlers/default_request_handler.py @@ -214,6 +214,12 @@ async def _setup_message_execution( await self._push_config_store.set_info( task.id, params.configuration.pushNotificationConfig ) + elif params.message.taskId: + raise ServerError( + error=InvalidParamsError( + message=f'Task {params.message.taskId} was specified but does not exist' + ) + ) # Build request context request_context = await self._request_context_builder.build( From 4287033944f95b8e9678d4fea7804d304307d8d9 Mon Sep 17 00:00:00 2001 From: Nathan Brake <33383515+njbrake@users.noreply.github.com> Date: Tue, 1 Jul 2025 13:39:45 -0400 Subject: [PATCH 2/3] Update src/a2a/server/request_handlers/default_request_handler.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/a2a/server/request_handlers/default_request_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/a2a/server/request_handlers/default_request_handler.py b/src/a2a/server/request_handlers/default_request_handler.py index 3f32d700..c32a9e66 100644 --- a/src/a2a/server/request_handlers/default_request_handler.py +++ b/src/a2a/server/request_handlers/default_request_handler.py @@ -216,7 +216,7 @@ async def _setup_message_execution( ) elif params.message.taskId: raise ServerError( - error=InvalidParamsError( + error=TaskNotFoundError( message=f'Task {params.message.taskId} was specified but does not exist' ) ) From fa0738f389d027461a32ed2e52a6604254543032 Mon Sep 17 00:00:00 2001 From: Nathan Brake Date: Thu, 17 Jul 2025 08:38:44 -0400 Subject: [PATCH 3/3] test both stream and non stream --- .../default_request_handler.py | 1 + .../test_default_request_handler.py | 82 +++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/src/a2a/server/request_handlers/default_request_handler.py b/src/a2a/server/request_handlers/default_request_handler.py index db9b86b6..d311691f 100644 --- a/src/a2a/server/request_handlers/default_request_handler.py +++ b/src/a2a/server/request_handlers/default_request_handler.py @@ -205,6 +205,7 @@ async def _setup_message_execution( error=TaskNotFoundError( message=f'Task {params.message.taskId} was specified but does not exist' ) + ) # Build request context request_context = await self._request_context_builder.build( diff --git a/tests/server/request_handlers/test_default_request_handler.py b/tests/server/request_handlers/test_default_request_handler.py index 06243d9d..2d9e9960 100644 --- a/tests/server/request_handlers/test_default_request_handler.py +++ b/tests/server/request_handlers/test_default_request_handler.py @@ -1779,3 +1779,85 @@ async def test_on_resubscribe_to_task_in_terminal_state(terminal_state): in exc_info.value.error.message ) mock_task_store.get.assert_awaited_once_with(task_id) + + +@pytest.mark.asyncio +async def test_on_message_send_task_id_provided_but_task_not_found(): + """Test on_message_send when taskId is provided but task doesn't exist.""" + task_id = 'nonexistent_task' + mock_task_store = AsyncMock(spec=TaskStore) + + request_handler = DefaultRequestHandler( + agent_executor=DummyAgentExecutor(), task_store=mock_task_store + ) + + params = MessageSendParams( + message=Message( + role=Role.user, + messageId='msg_nonexistent', + parts=[Part(root=TextPart(text='Hello'))], + taskId=task_id, + contextId='ctx1', + ) + ) + + from a2a.utils.errors import ServerError + + # Mock TaskManager.get_task to return None (task not found) + with patch( + 'a2a.server.request_handlers.default_request_handler.TaskManager.get_task', + return_value=None, + ): + with pytest.raises(ServerError) as exc_info: + await request_handler.on_message_send( + params, create_server_call_context() + ) + + assert isinstance(exc_info.value.error, TaskNotFoundError) + assert exc_info.value.error.message + assert ( + f'Task {task_id} was specified but does not exist' + in exc_info.value.error.message + ) + + +@pytest.mark.asyncio +async def test_on_message_send_stream_task_id_provided_but_task_not_found(): + """Test on_message_send_stream when taskId is provided but task doesn't exist.""" + task_id = 'nonexistent_stream_task' + mock_task_store = AsyncMock(spec=TaskStore) + + request_handler = DefaultRequestHandler( + agent_executor=DummyAgentExecutor(), task_store=mock_task_store + ) + + params = MessageSendParams( + message=Message( + role=Role.user, + messageId='msg_nonexistent_stream', + parts=[Part(root=TextPart(text='Hello'))], + taskId=task_id, + contextId='ctx1', + ) + ) + + from a2a.utils.errors import ServerError + + # Mock TaskManager.get_task to return None (task not found) + with patch( + 'a2a.server.request_handlers.default_request_handler.TaskManager.get_task', + return_value=None, + ): + with pytest.raises(ServerError) as exc_info: + # Need to consume the async generator to trigger the error + async for _ in request_handler.on_message_send_stream( + params, create_server_call_context() + ): + pass + + assert isinstance(exc_info.value.error, TaskNotFoundError) + assert exc_info.value.error.message + assert ( + f'Task {task_id} was specified but does not exist' + in exc_info.value.error.message + )