Skip to content

[BUG][Python] Case-sensitive request header merging duplicates fields and mutates input #25162

Description

@danielpassy

Problem

The Python generator merges request-header dicts case-sensitively. Forwarding content-type: application/json into a generated JSON operation adds Content-Type: application/json; HTTPX exposes application/json, application/json. Defaults and authentication can cause similar conflicts. The shared serializers also mutate supplied dicts, although public Pydantic-decorated calls may copy them first.

Originally observed with 7.25.0 and reproduced on master a39800cd. The shared code affects urllib3, asyncio/aiohttp, httpx and httpx2. Transport handling also differs: lower-case form Content-Type can be misclassified as JSON by urllib3, while aiohttp adds another Content-Type.

Minimal reproduction

Using a generated Petstore client:

from petstore_api import ApiClient, Pet, PetApi

headers = {"content-type": "application/json"}
request = PetApi(ApiClient())._add_pet_serialize(
    pet=Pet(name="test", photoUrls=[]), _headers=headers,
    _content_type=None, _request_auth=None, _host_index=0,
)
print(request[2])  # contains both content-type and Content-Type
print(headers)     # serializer added generated/default headers

Expected: one effective Content-Type and unchanged input. An HTTPX call with the same _headers produces the duplicate wire values described above.

Proposed correction

PR #25163 applies a common case-insensitive, request-local merge across these four libraries, with native header containers in each transport. Existing same-spelling precedence is retained: per-call → explicit/generated headers → defaults → client cookie → authentication. Later dict entries win; default-header setters replace earlier case variants. Legitimate comma-separated values and repeated transport fields are preserved. Public validation is unchanged.

Regression coverage includes precedence, authentication, input preservation, concurrent calls and lower-case form/multipart handling.

Related: TS/JS #6571, Go #24766, Go follow-up #24791. The latter informed the compatibility and deterministic-precedence approach. Searches of open/closed Python header and HTTPX issues/PRs did not find an equivalent fix in the results reviewed; this does not claim no other report exists.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions