From 1edcfa1c8b4b393996e28b01701b03a4681def6a Mon Sep 17 00:00:00 2001 From: "shuwen.wu" Date: Wed, 2 Sep 2026 15:38:00 +0800 Subject: [PATCH 1/2] fix(exceptions): coerce APIError.code to str to match Optional[str] annotation Replace construct_type call with explicit str coercion to properly handle numeric code values returned by the API. Fixes #3781 --- src/openai/_exceptions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openai/_exceptions.py b/src/openai/_exceptions.py index 7a30e4a336..5f5f911faf 100644 --- a/src/openai/_exceptions.py +++ b/src/openai/_exceptions.py @@ -69,7 +69,8 @@ def __init__(self, message: str, request: httpx2.Request, *, body: object | None self.body = body if is_dict(body): - self.code = cast(Any, construct_type(type_=Optional[str], value=body.get("code"))) + raw_code = body.get("code") + self.code = str(raw_code) if raw_code is not None else None self.param = cast(Any, construct_type(type_=Optional[str], value=body.get("param"))) self.type = cast(Any, construct_type(type_=str, value=body.get("type"))) else: From 4eee6b354edb7f99e0d6108f76d7c1cf1c0453b2 Mon Sep 17 00:00:00 2001 From: "shuwen.wu" Date: Wed, 2 Sep 2026 15:47:36 +0800 Subject: [PATCH 2/2] fix(auth): reject non-positive and non-finite token exchange expires_in Validate expires_in to reject negative values, zero, NaN, infinity, and overflow values (e.g. 10**400). Convert bool to int first since bool is a subclass of int. Fixes #3735 --- src/openai/auth/_workload.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/openai/auth/_workload.py b/src/openai/auth/_workload.py index 4f9797f092..f8d047ac1e 100644 --- a/src/openai/auth/_workload.py +++ b/src/openai/auth/_workload.py @@ -1,5 +1,6 @@ from __future__ import annotations +import math import time import threading from typing import Any, Generic, TypeVar, Callable, TypedDict, cast @@ -305,8 +306,10 @@ def _handle_token_response(self, response: httpx2.Response) -> dict[str, Any]: ) def _validate_expires_in(self, expires_in: object) -> float: - if not isinstance(expires_in, (int, float)): - raise OpenAIError("Token exchange response did not include a valid expires_in") + if isinstance(expires_in, bool): + expires_in = int(expires_in) + if not isinstance(expires_in, (int, float)) or math.isnan(expires_in) or math.isinf(expires_in) or expires_in <= 0: + raise ValueError("Token exchange response did not include a valid expires_in") return float(expires_in) def _token_unusable(self) -> bool: