📋 Prerequisites
🎯 Affected Service(s)
Controller Service
🚦 Impact/Severity
Blocker
🐛 Bug Description
Tasks created and persisted through the kagent controller A2A endpoint are
visible through store-backed ListTasks and through an authenticated REST
GET /api/tasks/{id}, but they cannot be resolved through exact A2A
GetTask or used to resume a persisted input-required task.
The failure is independent of the A2A wire version. It reproduced across all
four create/resume combinations:
- A2A 0.3 → A2A 0.3
- A2A 0.3 → A2A 1.0
- A2A 1.0 → A2A 0.3
- A2A 1.0 → A2A 1.0
The apparent cause is an ownership/identity mismatch. The controller persists
the task under the authenticated initiating principal, while the runtime later
performs its REST task lookup using the runtime service account. Because task
access is owner-scoped, that lookup reports that the existing task was not
found.
This prevents A2A clients from safely resuming controller-routed human-in-the-loop
interactions. Re-sending the original request is not a safe workaround because
it creates a new task and could duplicate an already accepted action.
Scope clarification
The defects are now tracked separately:
This issue should remain open while the applicable legacy-path fix and regression
coverage are evaluated.
🔄 Steps To Reproduce
-
Deploy kagent v0.10.0-rc1 with controller task persistence and authenticated,
owner-scoped task access enabled.
-
Through the controller A2A endpoint, send a message to an agent that produces
an input-required task. Retain the returned taskId and contextId.
-
From a fresh client process authenticated as the same initiating principal:
- Call
ListTasks/tasks/list with the retained contextId.
- Confirm that the expected task is returned in
input-required.
- Call
GetTask/tasks/get with the exact retained taskId.
-
Observe that exact GetTask returns JSON-RPC error -32001 task_not_found,
despite ListTasks returning the task.
-
Send a resume message containing the same taskId and contextId.
-
Observe that resume fails. Controller logs show the runtime attempting
GET /api/tasks/<taskId> and receiving Task not found.
-
Repeat with the four create/resume wire combinations:
0.3→0.3, 0.3→1.0, 1.0→0.3, and 1.0→1.0.
All combinations reproduce the failure.
🤔 Expected Behavior
An exact A2A GetTask request should retrieve a controller-persisted task when
the caller is authorized to access it.
A resume message containing the original taskId and contextId should resolve
that persisted input-required task and continue the same interaction,
regardless of whether the compatible 0.3 or 1.0 wire is used.
📱 Actual Behavior
Store-backed ListTasks returns the expected task, but exact A2A GetTask returns:
-32001 task_not_found
Attempting to resume the same task also fails. The controller logs show the
runtime performing:
GET /api/tasks/<redacted-task-id> → Task not found
Database inspection confirms that the task exists. An authenticated REST
request made as the initiating principal can retrieve it.
The observed ownership differs between controller-created and direct-runtime
tasks:
- Controller-created task: owned by the initiating controller-route principal
- Runtime lookup: authenticated as the agent runtime service account
This causes the owner-scoped lookup to return not found.
💻 Environment
- OS and version: macOS, client workstation
- Kubernetes version/provider: Internal environment; available privately if needed
- Browser: Not applicable
- Application version: kagent
v0.10.0-rc1
- Deployment mode: Helm/Kubernetes
- Authentication mode: trusted-proxy / service-account authentication
- Task persistence: PostgreSQL-backed controller task store
- A2A versions tested:
0.3 and 1.0
🔧 CLI Bug Report
Not attached because the reproduction occurred in an internal Kubernetes
environment and the generated report may contain internal infrastructure or
authentication details.
The issue includes sanitized, deterministic reproduction evidence. I can
provide a reviewed and redacted bug report privately if maintainers need
additional diagnostics.
🔍 Additional Context
The store-backed task-query wrapper currently appears to override only
ListTasks. Exact GetTask, CancelTask, and SubscribeToTask continue
through the passthrough/runtime path.
The observed behavior also appears to contradict these existing source comments:
-
a2av0_tasks_list.go:
“tasks/get is left to the underlying v0 handler, which already routes it to
the store-backed GetTask”
-
task_query_store.go:
“GetTask, which already resolves to the same store via the passthrough”
The legacy package remains in current main source, but the supported
current-main controller-v2 uses a different gateway path. Source presence alone
is therefore not runtime evidence for current main.
The current controller-v2/runtime identity-lifecycle defect is tracked
separately in #2465.
For the legacy controller path tracked here, serve exact GetTask requests from
the controller's authoritative, owner-scoped persistent task store before
falling back to the runtime. Persisted resume additionally depends on the
authenticated request-identity contract tracked in #2465.
Focused regression-test expectations for this issue:
- Verify owner isolation, persistent hits, absent-identity and not-found fallback,
non-not-found error propagation, requested history shaping, artifact retention,
and non-mutation of stored tasks.
- For any maintained release that ships the legacy path, cover persisted exact
GetTask and HITL resume on both supported wires, including the four cross-wire
resume combinations.
Temporary client-side mitigation exists only for reads: a client can perform an
exact-ID match through ListTasks after GetTask returns -32001. There is no safe
equivalent for resume because replaying the message could duplicate an accepted
operation.
I can help validate a proposed fix against the dual-wire GetTask and four-way
HITL resume matrix.
Related current-main source:
Reproduction matrix
| Created with |
Read/resumed with |
ListTasks |
GetTask |
Resume |
| 0.3 |
0.3 |
task found |
-32001 |
failed |
| 0.3 |
1.0 |
task found |
-32001 |
failed |
| 1.0 |
0.3 |
task found |
-32001 |
failed |
| 1.0 |
1.0 |
task found |
-32001 |
failed |
📋 Logs
A2A GetTask:
JSON-RPC error: code=-32001, class=task_not_found
Controller/runtime lookup:
GET /api/tasks/<redacted-task-id> → Task not found
Persistence verification:
ListTasks(contextId=<redacted>) → exact task found, state=input-required
REST GET /api/tasks/<redacted-task-id> as initiating principal → task found
📷 Screenshots
No response
🙋 Are you willing to contribute?
📋 Prerequisites
🎯 Affected Service(s)
Controller Service
🚦 Impact/Severity
Blocker
🐛 Bug Description
Tasks created and persisted through the kagent controller A2A endpoint are
visible through store-backed
ListTasksand through an authenticated RESTGET /api/tasks/{id}, but they cannot be resolved through exact A2AGetTaskor used to resume a persistedinput-requiredtask.The failure is independent of the A2A wire version. It reproduced across all
four create/resume combinations:
The apparent cause is an ownership/identity mismatch. The controller persists
the task under the authenticated initiating principal, while the runtime later
performs its REST task lookup using the runtime service account. Because task
access is owner-scoped, that lookup reports that the existing task was not
found.
This prevents A2A clients from safely resuming controller-routed human-in-the-loop
interactions. Re-sending the original request is not a safe workaround because
it creates a new task and could duplicate an already accepted action.
Scope clarification
The defects are now tracked separately:
controller-v2/runtime path.
through the legacy controller path, for any maintained release confirmed to
ship that path.
This issue should remain open while the applicable legacy-path fix and regression
coverage are evaluated.
🔄 Steps To Reproduce
Deploy kagent
v0.10.0-rc1with controller task persistence and authenticated,owner-scoped task access enabled.
Through the controller A2A endpoint, send a message to an agent that produces
an
input-requiredtask. Retain the returnedtaskIdandcontextId.From a fresh client process authenticated as the same initiating principal:
ListTasks/tasks/listwith the retainedcontextId.input-required.GetTask/tasks/getwith the exact retainedtaskId.Observe that exact GetTask returns JSON-RPC error
-32001 task_not_found,despite ListTasks returning the task.
Send a resume message containing the same
taskIdandcontextId.Observe that resume fails. Controller logs show the runtime attempting
GET /api/tasks/<taskId>and receivingTask not found.Repeat with the four create/resume wire combinations:
0.3→0.3,0.3→1.0,1.0→0.3, and1.0→1.0.All combinations reproduce the failure.
🤔 Expected Behavior
An exact A2A GetTask request should retrieve a controller-persisted task when
the caller is authorized to access it.
A resume message containing the original
taskIdandcontextIdshould resolvethat persisted
input-requiredtask and continue the same interaction,regardless of whether the compatible 0.3 or 1.0 wire is used.
📱 Actual Behavior
Store-backed ListTasks returns the expected task, but exact A2A GetTask returns:
-32001 task_not_foundAttempting to resume the same task also fails. The controller logs show the
runtime performing:
GET /api/tasks/<redacted-task-id> → Task not foundDatabase inspection confirms that the task exists. An authenticated REST
request made as the initiating principal can retrieve it.
The observed ownership differs between controller-created and direct-runtime
tasks:
This causes the owner-scoped lookup to return not found.
💻 Environment
v0.10.0-rc10.3and1.0🔧 CLI Bug Report
Not attached because the reproduction occurred in an internal Kubernetes
environment and the generated report may contain internal infrastructure or
authentication details.
The issue includes sanitized, deterministic reproduction evidence. I can
provide a reviewed and redacted bug report privately if maintainers need
additional diagnostics.
🔍 Additional Context
The store-backed task-query wrapper currently appears to override only
ListTasks. ExactGetTask,CancelTask, andSubscribeToTaskcontinuethrough the passthrough/runtime path.
The observed behavior also appears to contradict these existing source comments:
a2av0_tasks_list.go:“tasks/get is left to the underlying v0 handler, which already routes it to
the store-backed GetTask”
task_query_store.go:“GetTask, which already resolves to the same store via the passthrough”
The legacy package remains in current
mainsource, but the supportedcurrent-main controller-v2 uses a different gateway path. Source presence alone
is therefore not runtime evidence for current
main.The current controller-v2/runtime identity-lifecycle defect is tracked
separately in #2465.
For the legacy controller path tracked here, serve exact
GetTaskrequests fromthe controller's authoritative, owner-scoped persistent task store before
falling back to the runtime. Persisted resume additionally depends on the
authenticated request-identity contract tracked in #2465.
Focused regression-test expectations for this issue:
non-not-found error propagation, requested history shaping, artifact retention,
and non-mutation of stored tasks.
GetTaskand HITL resume on both supported wires, including the four cross-wireresume combinations.
Temporary client-side mitigation exists only for reads: a client can perform an
exact-ID match through ListTasks after GetTask returns
-32001. There is no safeequivalent for resume because replaying the message could duplicate an accepted
operation.
I can help validate a proposed fix against the dual-wire GetTask and four-way
HITL resume matrix.
Related current-main source:
Reproduction matrix
-32001-32001-32001-32001📋 Logs
📷 Screenshots
No response
🙋 Are you willing to contribute?