Skip to content

Default headers incorrectly override per-request custom headers #219

@dyeam0

Description

@dyeam0

Checklist

Describe the problem you'd like to have solved

Summary

The Python OpenFGA SDK has a bug in the header merging logic where default headers incorrectly take precedence over per-request custom headers. This violates the expected behavior where per-request headers should override default headers when there are conflicts.

Background

When users send custom headers via the options["headers"] parameter, they expect these headers to take precedence over any default headers set on the client. However, the current implementation in ApiClient.__call_api merges headers in the wrong order:

# Current buggy implementation (lines ~400-449 in api_client.py)
header_params = header_params or {}
header_params.update(self.default_headers)  # BUG: default headers override custom headers

This means if a user sets a custom header that conflicts with a default header, the default header value will be used instead of the custom one.

Impact

  • Users cannot override default headers with per-request custom headers
  • Breaks expected behavior for tracing, correlation IDs, and other custom headers
  • Makes it impossible to customize headers on a per-request basis when conflicts exist
  • Violates the principle of least surprise - users expect their explicit headers to take precedence

Example of the Bug

# Set a default header
fga_client.api_client.set_default_header("x-service-name", "default-service")

# Try to override it with a custom header
options = {
    "headers": {
        "x-service-name": "custom-service"  # This should take precedence but doesn't
    }
}

# The request will use "default-service" instead of "custom-service"
response = await fga_client.check(body, options)

Describe the ideal solution

Example of possible fix

The header merging logic should be corrected to give precedence to per-request headers:

# Fixed implementation
header_params = header_params or {}
# Merge headers with custom headers taking precedence over defaults
merged_headers = self.default_headers.copy()
merged_headers.update(header_params)
header_params = merged_headers

Expected Header Precedence Order

  1. Authentication headers (highest precedence) - applied via update_params_for_auth
  2. Per-request custom headers (via options["headers"]) - should override defaults
  3. Default headers (lowest precedence) - fallback values

Success Criteria

  • Per-request headers override conflicting default headers
  • Authentication headers maintain highest precedence
  • Existing functionality remains unchanged for non-conflicting headers
  • All existing tests continue to pass
  • New tests validate the correct precedence behavior

Alternatives and current workarounds

Current Workarounds

  • Clear default headers before making requests with custom headers (not viable in many situations)

References

Additional context

Code Location

The bug is in openfga_sdk/api_client.py in the ApiClient.__call_api method, approximately around lines 400-449.

Testing

Verification 1:

  1. Set a default header on the client
  2. Make a request with a custom header that has the same name
  3. Observe that the custom header value is used instead of the default one

Verification 2 (regression test):

  1. Set a default header on the client
  2. Make a request with a custom header that does NOT conflict with the default header
  3. Observe that both headers are present in the request

Verification 3 (regression test - only custom header):

  1. Clear out any default headers and do not set any new default headers on the client
  2. Make a request with a custom header
  3. Observe that the custom header is present in the request

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status

    Intake

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions