openai/openai-python · error · ValueError
The `default_headers` and `set_default_headers` arguments ar
Error message
The `default_headers` and `set_default_headers` arguments are mutually exclusive
What it means
`client.copy()` accepts either `default_headers` (merged over the existing headers) or `set_default_headers` (replaces them) — passing both is ambiguous, so it raises ValueError before creating the clone.
Source
Thrown at src/openai/_client.py:706
websocket_base_url: str | httpx2.URL | None = None,
base_url: str | httpx2.URL | None | NotGiven = not_given,
data_residency: DataResidency | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
http_client: httpx2.Client | None = None,
max_retries: int | NotGiven = not_given,
default_headers: Mapping[str, str] | None = None,
set_default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
set_default_query: Mapping[str, object] | None = None,
_enforce_credentials: bool | None = None,
_extra_kwargs: Mapping[str, Any] = {},
) -> Self:
"""
Create a new client instance re-using the same options given to the current client with optional overriding.
`data_residency` replaces the inherited HTTP and WebSocket endpoints, without changing this client.
"""
if default_headers is not None and set_default_headers is not None:
raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive")
if default_query is not None and set_default_query is not None:
raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive")
provider_changed = not isinstance(provider, NotGiven) and provider is not self._provider
inherited_organization = None if provider_changed else self.organization
inherited_project = None if provider_changed else self.project
headers: Mapping[str, str] = {} if provider_changed else self._custom_headers
if (
is_x509_workload_identity(workload_identity)
and not is_x509_workload_identity(self.workload_identity)
and self._ambient_authorizations
):
headers = {
name: value
for name, value in headers.items()
if name.lower() != "authorization" or value not in self._ambient_authorizationsView on GitHub (pinned to 9917c6e28e)
Solutions
- Choose one: `copy(default_headers={'X-Extra': v'})` to merge, or `copy(set_default_headers={...})` to replace
- In shared helpers, resolve to a single parameter before calling copy
Example fix
# before
new = client.copy(default_headers={'X-A': '1'}, set_default_headers={'X-B': '2'})
# after
new = client.copy(set_default_headers={'X-A': '1', 'X-B': '2'}) Defensive patterns
Strategy: validation
Validate before calling
assert not (default_headers is not None and set_default_headers is not None), \
'copy(): default_headers XOR set_default_headers' Prevention
- Remember semantics: default_headers merges, set_default_headers replaces
- In clone helpers, accept a single headers mapping plus a replace flag
When it happens
Trigger: `client.copy(default_headers={...}, set_default_headers={...})`; wrapper/clone helpers forwarding both kwargs from callers.
Common situations: Config-layer code building derived clients that forwards any header kwargs it received; refactor from one parameter to the other leaving both populated.
Related errors
- The `default_query` and `set_default_query` arguments are mu
- `provider` cannot be combined with top-level {formatted}. Mo
- The `api_key` and `workload_identity` arguments are mutually
- Could not find {header} header
- Pagination is only supported with mappings
AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28).
Data as JSON: /api/errors/c45f9691d4c566ad.
Report an issue: GitHub.