googleapis / googleapis/python-genai

Interactions client sends duplicate User-Agent header (breaks aiohttp 3.13.4+ servers)

Open
#2,309 1 comment 0 reactions 1 assignee Claimed by @Venkaiahbabuneelam View on GitHub
priority: p2 type: bug
Dominant language
Python
Stars
4k
Forks
1k
Avg merge
2d 11h
Merged PRs (30d)
40

Description

## Description

The Interactions API client sends two `User-Agent` HTTP headers on every request, which causes strict HTTP servers (aiohttp 3.13.4+) to reject the request with `400 Bad Request: Duplicate 'User-Agent' header found`.

## Root cause

`append_library_version_headers()` in `_api_client.py` adds a **lowercase** `user-agent` key to the headers dict:

```python
headers['user-agent'] = f'{library_label} {language_label}'
```

The Stainless-generated base class (`AsyncAPIClient.default_headers`) adds a **title-case** `User-Agent` key via its `user_agent` property:

```python
@property
def default_headers(self) -> dict[str, str | Omit]:
return {
"User-Agent": self.user_agent,
...
**self._custom_headers, # ← contains lowercase 'user-agent' from adapter
}
```

Since Python dicts are case-sensitive, the merged dict has both `User-Agent` and `user-agent` as separate keys. When passed to `httpx.Headers()`, they become two distinct header entries on the wire:

```
user-agent: AsyncGeminiNextGenAPIClient/Python 1.71.0
user-agent: google-genai-sdk/1.71.0 gl-python/3.14.3
```

## Reproduction

```python
from google import genai
from google.genai import types
import httpx

client = genai.Client(
api_key="test",
http_options=types.HttpOptions(api_version="v1beta", base_url="http://localhost:8080"),
)

ic = client.aio.interactions._client
h = httpx.Headers(ic.default_headers)
print(h.get_list("user-agent"))
# ['AsyncGeminiNextGenAPIClient/Python 1.71.0', 'google-genai-sdk/1.71.0 gl-python/3.14.3']
```

## Impact

- Any HTTP server using aiohttp 3.13.4+ as request parser rejects the request per RFC 9110 §5.5
- Affects all users of the Interactions API talking to proxies, test servers, or middleware that enforce singleton headers
- Reported independently in home-assistant/core#166866

## Affected versions

Tested on 1.71.0 and 1.72.0. Likely present since Interactions API was introduced.

## Suggested fix

Unify the User-Agent to a single key in `append_library_version_headers()`:

```python
# Use title-case to match the Stainless base class key
headers['User-Agent'] = f'{library_label} {language_label}'
# Or remove the base class User-Agent and let the adapter be the sole source
```

## Environment

- google-genai: 1.71.0 / 1.72.0
- Python: 3.14.3
- aiohttp (server): 3.13.4+ (rejects), 3.13.3 (accepts)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.