Component
SDKs
Priority
P2 - Medium (Would be helpful)
SDK Language(s)
Python
Bug Description
Problem
For a spec with two auth schemes under OR semantics (e.g. API key/basic or OAuth), the generated BaseClientWrapper.get_headers emits:
headers["Authorization"] = httpx.BasicAuth(self._get_api_key(), "")._auth_header
# _get_api_key(self) -> typing.Optional[str]
httpx.BasicAuth requires str | bytes, but the per-scheme getter is Optional[str] (you can satisfy auth via the other scheme). This:
- fails the generated SDK's own
mypy . (Argument 1 to "BasicAuth" has incompatible type "str | None"; expected "str | bytes" [arg-type]), and
- crashes at runtime on the token-only path (
httpx.BasicAuth(None, "") raises TypeError, and get_headers runs on every request, sync and async).
Root cause
In generators/python/src/fern_python/generators/sdk/core_utilities/client_wrapper_generator.py, _get_write_get_headers_body decides whether to null-guard the BasicAuth assignment based only on is_auth_mandatory / the optional-auth config (guarded branch ~lines 1017–1051; unguarded branch ~lines 1052–1075). It ignores whether the credential getter is actually optional. With OR auth (AuthSchemesRequirement.ANY, multiple schemes), is_auth_mandatory is True and optional-auth defaults False, so it takes the unguarded branch even though the getter is Optional[str].
Proposed fix
Guard the BasicAuth assignment whenever a non-omitted credential getter is optional, reusing the existing guarded emission:
api_key = self._get_api_key()
if api_key is not None:
headers["Authorization"] = httpx.BasicAuth(api_key, "")._auth_header
i.e. treat per-scheme getters as optional when the requirement is ANY with multiple schemes. This is type-correct (mypy narrows to str) and runtime-correct (no None basic header; the bearer block still takes precedence). Prefer this over a typing.cast, which hides the None runtime path.
Repro
Generate a Python SDK from a spec with API-key/basic OR OAuth, is_auth_mandatory: true, no optional-auth; inspect core/client_wrapper.py → get_headers and run mypy.
Versions
Fern CLI version 5.90.1
Fern python sdk version 5.27.1
Workaround
Setting optional-auth: true in the generator config forces the guarded emission, but the generator shouldn't require that flag to produce type-safe code for a valid OR-auth spec.
Are you interested in contributing a fix?
No
Component
SDKs
Priority
P2 - Medium (Would be helpful)
SDK Language(s)
Python
Bug Description
Problem
For a spec with two auth schemes under OR semantics (e.g. API key/basic or OAuth), the generated
BaseClientWrapper.get_headersemits:httpx.BasicAuthrequiresstr | bytes, but the per-scheme getter isOptional[str](you can satisfy auth via the other scheme). This:mypy .(Argument 1 to "BasicAuth" has incompatible type "str | None"; expected "str | bytes" [arg-type]), andhttpx.BasicAuth(None, "")raisesTypeError, andget_headersruns on every request, sync and async).Root cause
In
generators/python/src/fern_python/generators/sdk/core_utilities/client_wrapper_generator.py,_get_write_get_headers_bodydecides whether to null-guard theBasicAuthassignment based only onis_auth_mandatory/ theoptional-authconfig (guarded branch ~lines 1017–1051; unguarded branch ~lines 1052–1075). It ignores whether the credential getter is actually optional. With OR auth (AuthSchemesRequirement.ANY, multiple schemes),is_auth_mandatoryisTrueandoptional-authdefaultsFalse, so it takes the unguarded branch even though the getter isOptional[str].Proposed fix
Guard the
BasicAuthassignment whenever a non-omitted credential getter is optional, reusing the existing guarded emission:i.e. treat per-scheme getters as optional when the requirement is
ANYwith multiple schemes. This is type-correct (mypy narrows tostr) and runtime-correct (noNonebasic header; the bearer block still takes precedence). Prefer this over atyping.cast, which hides theNoneruntime path.Repro
Generate a Python SDK from a spec with API-key/basic OR OAuth,
is_auth_mandatory: true, nooptional-auth; inspectcore/client_wrapper.py→get_headersand runmypy.Versions
Fern CLI version 5.90.1
Fern python sdk version 5.27.1
Workaround
Setting
optional-auth: truein the generator config forces the guarded emission, but the generator shouldn't require that flag to produce type-safe code for a valid OR-auth spec.Are you interested in contributing a fix?
No