Skip to content

[BUG] KAgentTaskResponse validation error: data.kind empty after ask_user interrupt when resuming task #2037

Description

@Daniel-Vaz

📋 Prerequisites

  • I have searched the existing issues to avoid creating a duplicate
  • By submitting this issue, you agree to follow our Code of Conduct
  • I am using the latest version of the software
  • I have tried to clear cache/cookies or used incognito mode (if ui-related)
  • I can consistently reproduce this issue

🎯 Affected Service(s)

Controller Service

🚦 Impact/Severity

Blocker

🐛 Bug Description

When an agent triggers an ask_user interrupt (HITL), the task cannot be resumed after the user answers. The kagent Python engine fails with a Pydantic validation error:

pydantic_core._pydantic_core.ValidationError: 1 validation error for KAgentTaskResponse
data.kind
  Input should be 'task' [type=literal_error, input_value='', input_type=str]

This surfaces as an SSE stream error on the client side:

SSE stream error: unexpected EOF (INTERNAL_ERROR)

🔄 Steps To Reproduce

  1. Invoke an agent that calls the ask_user tool
  2. Agent enters input_required state and pauses
  3. User submits answers

🤔 Expected Behavior

The task resumes, the agent processes the answers and continues.

📱 Actual Behavior

task_store.get() fails with a Pydantic validation error because data.kind is an empty string instead of "task".

💻 Environment

  • kagent versio 0.9.8

🔧 CLI Bug Report

No response

🔍 Additional Context

This appears to be a regression introduced by #1921 (Migrate from A2A v0 to v1).

The round-trip through the Go controller loses the kind field:

  1. The Python engine's task_store.save() sends POST /api/tasks without an A2A-Version header
  2. NegotiateA2AWireVersion() in the Go controller defaults to A2AWireVersionLegacy (v0) because no header is present
  3. HandleCreateTask decodes the body as a legacy protocol.Task and converts it to Go's a2a.Task (v1) via trpcv0.ToV1Task() — during this conversion, the kind discriminator is not carried over into the stored JSON
  4. HandleGetTask later retrieves the task and attempts trpcv0.ToLegacyTask(), but since kind was dropped at write time, the Python-side KAgentTaskResponse.model_validate() receives data.kind = "" instead of "task"

The relevant code path:

📋 Logs

ERROR:    Exception in ASGI application
  + Exception Group Traceback (most recent call last):
  |   File "/.kagent/.venv/lib/python3.13/site-packages/uvicorn/protocols/http/h11_impl.py", line 415, in run_asgi
  |     result = await app(  # type: ignore[func-returns-value]
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |         self.scope, self.receive, self.send
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |     )
  |     ^
  |   File "/.kagent/.venv/lib/python3.13/site-packages/uvicorn/middleware/proxy_headers.py", line 56, in __call__
  |     return await self.app(scope, receive, send)
  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |   File "/.kagent/.venv/lib/python3.13/site-packages/fastapi/applications.py", line 1159, in __call__
  |     await super().__call__(scope, receive, send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/applications.py", line 107, in __call__
  |     await self.middleware_stack(scope, receive, send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/middleware/errors.py", line 186, in __call__
  |     raise exc
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/middleware/errors.py", line 164, in __call__
  |     await self.app(scope, receive, _send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/opentelemetry/instrumentation/asgi/__init__.py", line 795, in __call__
  |     await self.app(scope, otel_receive, otel_send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/middleware/errors.py", line 186, in __call__
  |     raise exc
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/middleware/errors.py", line 164, in __call__
  |     await self.app(scope, receive, _send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/opentelemetry/instrumentation/fastapi/__init__.py", line 307, in __call__
  |     await self.app(scope, receive, send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/middleware/exceptions.py", line 63, in __call__
  |     await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
  |     raise exc
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
  |     await app(scope, receive, sender)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
  |     await self.app(scope, receive, send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/routing.py", line 716, in __call__
  |     await self.middleware_stack(scope, receive, send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/routing.py", line 736, in app
  |     await route.handle(scope, receive, send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/routing.py", line 290, in handle
  |     await self.app(scope, receive, send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/fastapi/routing.py", line 134, in app
  |     await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
  |     raise exc
  |   File "/.kagent/.venv/lib/python3.13/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
  |     await app(scope, receive, sender)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/fastapi/routing.py", line 121, in app
  |     await response(scope, receive, send)
  |   File "/.kagent/.venv/lib/python3.13/site-packages/sse_starlette/sse.py", line 255, in __call__
  |     async with anyio.create_task_group() as task_group:
  |                ~~~~~~~~~~~~~~~~~~~~~~~^^
  |   File "/.kagent/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 799, in __aexit__
  |     raise BaseExceptionGroup(
  |         "unhandled errors in a TaskGroup", self._exceptions
  |     ) from None
  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "/.kagent/.venv/lib/python3.13/site-packages/sse_starlette/sse.py", line 258, in cancel_on_finish
    |     await coro()
    |   File "/.kagent/.venv/lib/python3.13/site-packages/sse_starlette/sse.py", line 177, in _stream_response
    |     async for data in self.body_iterator:
    |     ...<10 lines>...
    |             raise SendTimeoutError()
    |   File "/.kagent/.venv/lib/python3.13/site-packages/a2a/server/apps/jsonrpc/jsonrpc_app.py", line 542, in event_generator
    |     async for item in stream:
    |         yield {'data': item.root.model_dump_json(exclude_none=True)}
    |   File "/.kagent/.venv/lib/python3.13/site-packages/a2a/server/request_handlers/jsonrpc_handler.py", line 147, in on_message_send_stream
    |     async for event in self.request_handler.on_message_send_stream(
    |     ...<13 lines>...
    |         )
    |   File "/.kagent/.venv/lib/python3.13/site-packages/a2a/server/request_handlers/default_request_handler.py", line 375, in on_message_send_stream
    |     ) = await self._setup_message_execution(params, context)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/.kagent/.venv/lib/python3.13/site-packages/a2a/utils/telemetry.py", line 228, in async_wrapper
    |     result = await func(*args, **kwargs)
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/.kagent/.venv/lib/python3.13/site-packages/a2a/server/request_handlers/default_request_handler.py", line 217, in _setup_message_execution
    |     task: Task | None = await task_manager.get_task()
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/.kagent/.venv/lib/python3.13/site-packages/a2a/server/tasks/task_manager.py", line 81, in get_task
    |     self._current_task = await self.task_store.get(
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |         self.task_id, self._call_context
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     )
    |     ^
    |   File "/.kagent/packages/kagent-core/src/kagent/core/a2a/_task_store.py", line 95, in get
    |     wrapped = KAgentTaskResponse.model_validate(response.json())
    |   File "/.kagent/.venv/lib/python3.13/site-packages/pydantic/main.py", line 732, in model_validate
    |     return cls.__pydantic_validator__.validate_python(
    |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
    |         obj,
    |         ^^^^
    |     ...<5 lines>...
    |         by_name=by_name,
    |         ^^^^^^^^^^^^^^^^
    |     )
    |     ^
    | pydantic_core._pydantic_core.ValidationError: 1 validation error for KAgentTaskResponse
    | data.kind
    |   Input should be 'task' [type=literal_error, input_value='', input_type=str]
    |     For further information visit https://errors.pydantic.dev/2.13/v/literal_error
    +------------------------------------

📷 Screenshots

No response

🙋 Are you willing to contribute?

  • I am willing to submit a PR to fix this issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No fields configured for Bug.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions