Skip to content

fix(grpc): normalize extension metadata header key to lowercase#673

Open
cchinchilla-dev wants to merge 5 commits intoa2aproject:mainfrom
cchinchilla-dev:fix/grpc-lowercase-metadata-key
Open

fix(grpc): normalize extension metadata header key to lowercase#673
cchinchilla-dev wants to merge 5 commits intoa2aproject:mainfrom
cchinchilla-dev:fix/grpc-lowercase-metadata-key

Conversation

@cchinchilla-dev
Copy link

Description

Fixes #656 🦕

Problem

gRPC requires metadata keys to be lowercase ASCII. The SDK uses the constant HTTP_EXTENSION_HEADER = 'X-A2A-Extensions' when attaching metadata in both the gRPC client transport and the server handler, causing a runtime error:

Metadata key 'X-A2A-Extensions' is invalid: INTERNAL: Illegal header key

This casing is valid for HTTP/REST (headers are case-insensitive per RFC 7230), but gRPC enforces lowercase and rejects anything with uppercase characters.

Fix

Applied .lower() to the metadata key at each gRPC boundary:

  • Clientsrc/a2a/client/transports/grpc.py_get_grpc_metadata: normalize key when attaching extension metadata to outgoing requests.
  • Server readsrc/a2a/server/request_handlers/grpc_handler.py_get_metadata_value: normalize key when reading extension metadata from incoming requests.
  • Server writesrc/a2a/server/request_handlers/grpc_handler.py_set_extension_metadata: normalize key when writing extension metadata to trailing response metadata.

The HTTP_EXTENSION_HEADER constant in common.py remains unchanged — it is still correct for HTTP/REST usage.

Alternative Considered

A dedicated constant in common.py (GRPC_EXTENSION_METADATA_KEY = HTTP_EXTENSION_HEADER.lower()) would make the intent more explicit. However, the inline .lower() approach is less invasive: it avoids introducing a new public constant, doesn't change the module's API surface, and keeps the fix tightly scoped to the gRPC paths. Happy to switch if maintainers prefer it.

Testing

Updated existing test assertions and added two new tests that explicitly verify the lowercase invariant:

  • test_grpc_metadata_key_is_lowercase
  • test_grpc_metadata_key_from_default_extensions_is_lowercase

All tests pass.

@cchinchilla-dev cchinchilla-dev requested a review from a team as a code owner February 8, 2026 17:59
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @cchinchilla-dev, 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 resolves a critical issue where gRPC services failed due to metadata header keys containing uppercase characters, a violation of gRPC's strict lowercase requirement. By systematically applying a lowercase transformation to the extension metadata header key across the gRPC client and server components, the system now adheres to gRPC specifications, preventing runtime errors and ensuring robust communication. The HTTP_EXTENSION_HEADER constant itself remains unchanged, preserving its validity for HTTP/REST contexts.

Highlights

  • gRPC Metadata Key Normalization: Addressed a runtime error in gRPC where metadata keys with uppercase characters were rejected. The fix ensures that the HTTP_EXTENSION_HEADER is consistently converted to lowercase at all gRPC interaction points.
  • Client-Side Metadata Handling: Modified the gRPC client transport (src/a2a/client/transports/grpc.py) to normalize the extension metadata key to lowercase when attaching it to outgoing requests.
  • Server-Side Metadata Handling: Updated the gRPC server handler (src/a2a/server/request_handlers/grpc_handler.py) to normalize the extension metadata key to lowercase both when reading incoming requests and when writing trailing response metadata.
  • Enhanced Test Coverage: Existing test assertions were updated to reflect the lowercase metadata key, and two new dedicated tests were added to explicitly verify that gRPC metadata keys are always lowercase.
Changelog
  • src/a2a/client/transports/grpc.py
    • Applied .lower() to HTTP_EXTENSION_HEADER when constructing gRPC metadata in _get_grpc_metadata.
  • src/a2a/server/request_handlers/grpc_handler.py
    • Modified _get_metadata_value to retrieve metadata using key.lower().
    • Applied .lower() to HTTP_EXTENSION_HEADER when setting trailing metadata in _set_extension_metadata.
  • tests/client/transports/test_grpc_client.py
    • Updated existing test assertions to expect HTTP_EXTENSION_HEADER.lower() for gRPC metadata.
    • Added test_get_grpc_metadata_uses_lowercase_header_key to verify the lowercase invariant for metadata keys.
  • tests/server/request_handlers/test_grpc_handler.py
    • Adjusted test cases to use HTTP_EXTENSION_HEADER.lower() when mocking invocation_metadata and asserting set_trailing_metadata calls.
Activity
  • No human activity (comments, reviews, etc.) 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 addresses the issue of gRPC metadata keys needing to be lowercase by applying .lower() where HTTP_EXTENSION_HEADER is used in gRPC contexts. The changes are logical and the added tests provide good coverage for the fix.

I've added a few minor suggestions to improve code clarity and reduce duplication. While the current implementation is correct, these refactorings could enhance long-term maintainability.

Also, as you mentioned in the description, introducing a constant for the lowercase header key (e.g., _GRPC_EXTENSION_HEADER = HTTP_EXTENSION_HEADER.lower()) within the gRPC-related modules could be a good way to make the code more DRY and the intent clearer, without polluting the public API. This is something to consider.

cchinchilla-dev and others added 2 commits February 8, 2026 19:08
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@cchinchilla-dev
Copy link
Author

/gemini review

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 addresses the issue of gRPC metadata keys needing to be lowercase. The changes are applied consistently across client and server code, and the test suite has been updated accordingly, including the addition of a new regression test. The code is clear and the fix is effective. I have one minor suggestion to improve the robustness of the new test case.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
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]: Metadata key 'X-A2A-Extensions' is invalid: INTERNAL: Illegal header key ( gRPC metadata key X-A2A-Extensions is invalid )

1 participant