Skip to content

fix: reject messages with mismatching contextId and taskId#729

Closed
ehsavoie wants to merge 1 commit intoa2aproject:mainfrom
ehsavoie:issue_723
Closed

fix: reject messages with mismatching contextId and taskId#729
ehsavoie wants to merge 1 commit intoa2aproject:mainfrom
ehsavoie:issue_723

Conversation

@ehsavoie
Copy link
Collaborator

Validate that the contextId provided in a SendMessage request matches the contextId of the referenced task, returning InvalidParamsError when they differ. Previously, the mismatch was silently ignored and the request succeeded.

Add tests covering both streaming and non-streaming paths across all transports.

Fixes #723 🦕

@ehsavoie ehsavoie requested review from jmesnil and kabir March 12, 2026 09:46
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a data integrity issue where SendMessage requests could silently succeed even when the contextId provided in the message did not match the contextId of the associated task. The changes introduce explicit validation to prevent such mismatches, ensuring that all SendMessage operations correctly reference their intended task context. This improves the robustness and predictability of message handling within the system by providing immediate feedback on invalid requests.

Highlights

  • Context ID Validation: Implemented validation in SendMessage requests to ensure the provided contextId matches the contextId of the referenced task.
  • Error Handling: Requests with mismatching contextId values will now explicitly fail with an InvalidParamsError instead of silently succeeding.
  • Comprehensive Testing: Added new unit and integration tests to cover both streaming and non-streaming message paths across gRPC, JSON-RPC, and REST transports, verifying the new validation logic.
Changelog
  • server-common/src/main/java/io/a2a/server/requesthandlers/DefaultRequestHandler.java
    • Added validation logic to the initMessageSend method to check for contextId mismatch between the incoming message and the current task.
  • server-common/src/test/java/io/a2a/server/requesthandlers/DefaultRequestHandlerTest.java
    • Imported assertThrows and InvalidParamsError for new test cases.
    • Added testContextIdMismatch_NonStreaming_ThrowsInvalidParamsError to verify non-streaming message rejection.
    • Added testContextIdMismatch_Streaming_ThrowsInvalidParamsError to verify streaming message rejection.
  • tests/server-common/src/test/java/io/a2a/server/apps/common/AbstractA2AServerTest.java
    • Added testSendMessageContextIdMismatch to test non-streaming client behavior with mismatching context IDs.
    • Added testSendStreamingMessageContextIdMismatch to test streaming client behavior with mismatching context IDs.
  • transport/grpc/src/test/java/io/a2a/transport/grpc/handler/GrpcHandlerTest.java
    • Added testSendMessageContextIdMismatch to verify gRPC non-streaming message handling for context ID mismatches.
    • Added testSendStreamingMessageContextIdMismatch to verify gRPC streaming message handling for context ID mismatches.
  • transport/jsonrpc/src/test/java/io/a2a/transport/jsonrpc/handler/JSONRPCHandlerTest.java
    • Imported InvalidParamsError for new test cases.
    • Added testOnMessageSendContextIdMismatch to verify JSON-RPC non-streaming message handling for context ID mismatches.
    • Added testOnMessageStreamContextIdMismatch to verify JSON-RPC streaming message handling for context ID mismatches.
  • transport/rest/src/test/java/io/a2a/transport/rest/handler/RestHandlerTest.java
    • Added testSendMessageContextIdMismatch to verify REST non-streaming message handling for context ID mismatches.
    • Added testSendStreamingMessageContextIdMismatch to verify REST streaming message handling for context ID mismatches.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly fixes a validation issue by rejecting messages with a contextId that mismatches the taskId's context. The core logic change in DefaultRequestHandler is sound, and the addition of comprehensive tests across all transports (gRPC, JSON-RPC, REST) for both streaming and non-streaming scenarios is excellent. I have one suggestion to simplify the logic in one of the new integration tests for better readability.

Comment on lines +602 to +613
Throwable cause = error;
boolean foundInvalidParams = false;
while (cause != null && !foundInvalidParams) {
if (cause instanceof InvalidParamsError) {
foundInvalidParams = true;
} else if (cause instanceof A2AClientException && cause.getCause() instanceof InvalidParamsError) {
foundInvalidParams = true;
}
cause = cause.getCause();
}
assertTrue(foundInvalidParams,
"Should receive InvalidParamsError for mismatching contextId and taskId");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic to walk the cause chain to find the InvalidParamsError is more complex than necessary. The else if condition is redundant because the next iteration of the while loop would check cause.getCause() anyway. You can simplify this loop for better readability and maintainability.

            Throwable cause = error;
            boolean foundInvalidParams = false;
            while (cause != null) {
                if (cause instanceof InvalidParamsError) {
                    foundInvalidParams = true;
                    break;
                }
                cause = cause.getCause();
            }
            assertTrue(foundInvalidParams,
                    "Should receive InvalidParamsError for mismatching contextId and taskId");

Validate that the contextId provided in a SendMessage request matches
the contextId of the referenced task, returning InvalidParamsError
when they differ. Previously, the mismatch was silently ignored and
the request succeeded.

Add tests covering both streaming and non-streaming paths across all
transports.

Signed-off-by: Emmanuel Hugonnet <ehugonne@redhat.com>
Copy link
Collaborator

@jmesnil jmesnil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The grpc, jsonrpc and rest tests are superfluous: they all end up using the same code path from the DefaultRequestHandler (for both streaming and non-streaming).

@ehsavoie
Copy link
Collaborator Author

@jmesnil I agree BUT if somehow this would change we are covered on all protocols.

@jmesnil
Copy link
Collaborator

jmesnil commented Mar 12, 2026

Right but this issue is not about transports, it is about validation. The transport tests bring no value. They can stay but I don't think we have to necessarily add transports tests whenever an issue if found in a deeper layer of the SDK.

@ehsavoie
Copy link
Collaborator Author

Superseded by #728

@ehsavoie ehsavoie closed this Mar 12, 2026
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.

[Bug]: SendMessage does not return an error when taskId and contextId are mismatched

2 participants