fix(compat): coerce by_alias=None to False in model_dump to fix TypeError with pydantic v2#2999
Conversation
Fixes openai#2921 model_dump() in _compat.py declares by_alias as bool | None = None and was forwarding the value as-is to pydantic's model_dump(). pydantic-core's Rust-based serializer (pydantic v2) does not accept None for by_alias and raises: TypeError: argument 'by_alias': 'NoneType' object cannot be converted to 'PyBool' This error only manifests when DEBUG-level logging is enabled on the openai logger, because the call that omits by_alias is inside a 'if log.isEnabledFor(logging.DEBUG)' block in _base_client.py. Fix: replace 'by_alias=by_alias' with an explicit coercion so that None becomes False (the natural default) instead of being forwarded to pydantic: by_alias=bool(by_alias) if by_alias is not None else False The pydantic v1 code path already used bool(by_alias), so this aligns both branches.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bee7537f80
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| warnings=True if PYDANTIC_V1 else warnings, | ||
| by_alias=by_alias, | ||
| # pydantic-core's Rust serializer rejects None for by_alias; coerce to bool. | ||
| by_alias=bool(by_alias) if by_alias is not None else False, |
There was a problem hiding this comment.
Preserve config-driven alias behavior in model_dump
When by_alias is omitted, supported Pydantic 2.11+ models can still serialize aliases via ConfigDict(serialize_by_alias=True). Forcing None to False here changes that contract: _compat.model_dump() no longer defers to the model config, and both _utils._transform._transform_recursive() and _async_transform_recursive() call this helper for arbitrary pydantic.BaseModel inputs when building request bodies. In that scenario, aliased third-party Pydantic models will now emit field names instead of aliases, which can send the wrong keys to the API.
Useful? React with 👍 / 👎.
Summary
Fixes #2921
Problem
model_dump()in_compat.pydeclaresby_alias: bool | None = Noneand was forwarding the value as-is to pydantic'smodel_dump(). pydantic-core's Rust-based serializer (pydantic v2) does not acceptNoneforby_aliasand raises:This error only manifests when DEBUG-level logging is enabled on the
openailogger, because the affected call site omitsby_alias(so it defaults toNone) and is inside aif log.isEnabledFor(logging.DEBUG)block in_base_client.py.Fix
Coerce
NonetoFalsebefore passing to pydantic:The pydantic v1 code path already used
bool(by_alias), so this aligns both branches.Testing