Skip to content

fix(server): reject a message whose contextId disagrees with its task - #1270

Merged
JakubWorek merged 2 commits into
jakubworek/acts-input-mode-validationfrom
jakubworek/acts-context-id-mismatch
Sep 29, 2026
Merged

JakubWorek merged 2 commits into
jakubworek/acts-input-mode-validationfrom
jakubworek/acts-context-id-mismatch

Conversation

@JakubWorek

@JakubWorek JakubWorek commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

What

Spec 3.4.3: "Agents MUST reject messages containing mismatching contextId and taskId (i.e., the provided contextId is different from that of the referenced Task)."

A follow-up carrying a real taskId with someone else's contextId was accepted with HTTP 200, and the client's contextId was then written into the task's history while the Task kept its own - two disagreeing context ids inside one task.

This guard already existed

RequestContext has carried it all along (agent_execution/context.py:77-78). It only fires when a non-None task reaches build(), and v2 passes task=None on purpose:

# We will get the task when we have to process the request to avoid concurrent read/write issues.
task=None,

So the check went dead when V2 became the default. The legacy handler passes the task and still rejects.

Rather than undo that deliberate task=None, the comparison goes where v2 already fetches the task to prove it exists, one line after the TaskNotFoundError it raises there. No extra read, and the task is not retained.

Scoped to requests that name a task

The check only runs under if original_task_id:. A contextId with no taskId is a new task in an existing context, which stays legal - test_scenario_context_id_visibility depends on it, and there is a test here pinning it.

A test that passed for the wrong reason

Worth flagging for review. TaskManager already rejects this mismatch once the agent emits an event, with Context in event doesn't match TaskManager wrong-context : real-context. That message happens to contain both context ids, so the obvious assertion - pytest.raises(InvalidParamsError) plus both ids in the message - passes with or without this change. It did, and mutation testing is what caught it.

The test now asserts the executor was never awaited. That is the actual behavioural difference: the request is refused before any agent work starts, instead of after the agent has already been handed a request whose ids contradict each other.

Result

Clears CORE-MULTI-006 (must) on all three bindings.

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

🧪 Code Coverage (vs jakubworek/acts-input-mode-validation)

⬇️ Download Full Report

Base PR Delta
src/a2a/server/request_handlers/default_request_handler_v2.py 92.68% 92.80% 🟢 +0.12%
Total 93.12% 93.12% ⚪️ 0.00%

Generated by coverage-comment.yml

@JakubWorek
JakubWorek added this pull request to stack #1275 September 23, 2026 12:55
@JakubWorek
JakubWorek force-pushed the jakubworek/acts-context-id-mismatch branch from 2deb1c4 to 59afee4 Compare September 23, 2026 13:11
@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
Comment thread src/a2a/server/request_handlers/default_request_handler_v2.py Outdated
Comment thread src/a2a/server/request_handlers/default_request_handler_v2.py Outdated
@JakubWorek
JakubWorek force-pushed the jakubworek/acts-context-id-mismatch branch 2 times, most recently from 248bf73 to 12777b4 Compare September 28, 2026 08:47
Spec 5.6 requires agents to reject mismatching contextId and taskId.
RequestContext has carried that guard all along, but v2 calls build()
with task=None on purpose, so nothing reached it and the client's
contextId was written into the task's history beside the task's own.

Checked against the task v2 already fetches to prove existence, and
only when a taskId is present: a contextId on its own starts a new task
in that context and stays legal.
@JakubWorek
JakubWorek force-pushed the jakubworek/acts-context-id-mismatch branch from 12617cd to 49dfc35 Compare September 28, 2026 10:14
@JakubWorek
JakubWorek merged commit c25022f into main Sep 29, 2026
34 of 36 checks passed
@JakubWorek
JakubWorek deleted the jakubworek/acts-context-id-mismatch 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.

2 participants