🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

fix(server): reject terminal-task operations with UnsupportedOperationError - #1268

Merged
JakubWorek merged 2 commits into
mainfrom
jakubworek/acts-terminal-state-error
Sep 29, 2026
Merged

JakubWorek merged 2 commits into
mainfrom
jakubworek/acts-terminal-state-error

Conversation

@JakubWorek

@JakubWorek JakubWorek commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

What

Spec 3.1.1 names UnsupportedOperationError for "Messages sent to Tasks that are in a terminal state", and 3.3.2 repeats it for any operation on a terminal task. 5.4 maps that to -32004 / FAILED_PRECONDITION / HTTP 400. ActiveTask raised InvalidParamsError (-32602) instead, at all three of its terminal-state guards.

That covers both send_message and subscribe_to_task, because DefaultRequestHandlerV2.on_subscribe_to_task has no terminal check of its own: it calls get_or_create, which calls ActiveTask.start(), and the error surfaces out of the first __anext__.

Worth knowing while reading: DefaultRequestHandler is an alias for DefaultRequestHandlerV2 (request_handlers/__init__.py:46), so default_request_handler.py is the legacy handler and is not on the default path. It already answered subscribe correctly at line 613, which is why only the v2 path drifted. Its send path is corrected here too, so the two handlers and the two operations finally agree.

Cancel keeps its own error

on_cancel_task deliberately catches ActiveTask's terminal-state error and re-raises TaskNotCancelableError, which 3.3.2 gives its own entry. That remap is retained, now keyed on the new error type. Two ACTS tests (CORE-CANCEL-002, CORE-ERR-002) cover it and still pass.

Tests

test_on_subscribe_to_task_in_terminal_state is new for v2. Its absence is why this survived: the legacy suite had the equivalent test and asserted the correct error all along, so the divergence never showed up. Mutation-checked - reverting active_task.py:472 alone fails all four parametrized cases.

An existing # TODO: Is it correct error code ? in test_scenarios.py sat next to this exact assertion. It is now answered rather than carried forward.

Result

Clears CORE-SEND-002, CORE-ERR-004 and STREAM-SUB-003 (all must) on jsonrpc, grpc and rest - 9 of the 21 failing MUST test-instances.

binding must before must after
jsonrpc 52/59 55/59
grpc 40/47 43/47
rest 42/49 45/49

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

🧪 Code Coverage (vs main)

⬇️ Download Full Report

No coverage changes.

Generated by coverage-comment.yml

@JakubWorek
JakubWorek added this pull request to stack #1275 September 23, 2026 12:55
@JakubWorek
JakubWorek marked this pull request as ready for review September 23, 2026 13:26
@JakubWorek
JakubWorek requested a review from a team as a code owner September 23, 2026 13:26
@ConnorMoss02

Copy link
Copy Markdown
Contributor

#1178 adds a terminal-state check in _setup_active_task that raises InvalidParamsError when a message with a push config is sent to a terminal task. Spec 3.1.1 gives that case UnsupportedOperationError.

Comment thread src/a2a/server/request_handlers/default_request_handler_v2.py Outdated
…nError

Spec 3.1.1 and 3.3.2 name UnsupportedOperationError for operations on a
task in a terminal state; ActiveTask raised InvalidParamsError instead,
so send_message and subscribe_to_task both returned -32602 rather than
-32004. The legacy handler already answered subscribe correctly, which
is why only the v2 path drifted.

on_cancel_task keeps its TaskNotCancelableError remap, now keyed on the
new error. Adds the v2 subscribe-to-terminal test whose absence let the
divergence survive.
@JakubWorek
JakubWorek force-pushed the jakubworek/acts-terminal-state-error branch from ce95dff to aaa88b6 Compare September 28, 2026 10:14
@JakubWorek
JakubWorek merged commit 6cce91b into main Sep 29, 2026
20 checks passed
@JakubWorek
JakubWorek deleted the jakubworek/acts-terminal-state-error branch September 29, 2026 07:20
mykytanetipa pushed a commit that referenced this pull request Sep 29, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.2.0](v1.1.5...v1.2.0)
(2026-09-29)


### Features

* **rest:** serve HTTP+JSON responses as application/a2a+json
([#1274](#1274))
([dc5a5da](dc5a5da))
* **server:** add caching headers to the agent card endpoint
([#1272](#1272))
([83d7f5d](83d7f5d))
* **server:** add multi-replica cluster mode
([#1281](#1281))
([942d621](942d621))
* **server:** add opt-in validation of message media types against the
agent card
([#1269](#1269))
([8037b24](8037b24))


### Bug Fixes

* compare in-memory task timestamps numerically
([#1233](#1233))
([0d5473c](0d5473c))
* **server:** ignore unrecognized request fields and fix parse-error
data shape
([#1273](#1273))
([83f1cf8](83f1cf8))
* **server:** reject a message whose contextId disagrees with its task
([#1270](#1270))
([c25022f](c25022f))
* **server:** reject terminal-task operations with
UnsupportedOperationError
([#1268](#1268))
([6cce91b](6cce91b))
* **server:** send PushNotificationConfig.authentication as an
Authorization header
([#1271](#1271))
([5751d31](5751d31)),
closes [#585](#585)


### Documentation

* **samples:** add Agent Card signing sample
([#1198](#1198))
([f3ac824](f3ac824))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants