-
Notifications
You must be signed in to change notification settings - Fork 27
Description
Checklist
- I agree to the terms within the OpenFGA Code of Conduct.
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
- Authentication headers (highest precedence) - applied via
update_params_for_auth
- Per-request custom headers (via
options["headers"]
) - should override defaults - 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
- Related issue: Add tests for per-request custom HTTP headers functionality #217
- Related issue: Add documentation and examples for per-request custom HTTP headers usage #215
- SDK generator feature request: Add support for per-request custom HTTP headers in SDK API calls sdk-generator#569
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:
- Set a default header on the client
- Make a request with a custom header that has the same name
- Observe that the custom header value is used instead of the default one
Verification 2 (regression test):
- Set a default header on the client
- Make a request with a custom header that does NOT conflict with the default header
- Observe that both headers are present in the request
Verification 3 (regression test - only custom header):
- Clear out any default headers and do not set any new default headers on the client
- Make a request with a custom header
- Observe that the custom header is present in the request
Metadata
Metadata
Assignees
Labels
Type
Projects
Status