Confirm this is an issue with the Python library and not an underlying OpenAI API
Describe the bug
APIStatusError.code is annotated Optional[str], but at runtime it can hold an int (or any other JSON type the server puts in error.code).
In openai/_exceptions.py the field is built with the lenient deserializer and an explicit cast(Any, ...):
self.code = cast(Any, construct_type(type_=Optional[str], value=body.get("code")))
construct_type returns the value unchanged when it doesn't match the target type — it neither coerces nor rejects — and the cast(Any, ...) suppresses the type checker, so nothing ever enforces the Optional[str] annotation. When an error body contains a JSON number ({"error": {"code": 404, ...}}), exc.code is an int.
This bit us in production: downstream code that trusted the annotation called exc.code.strip() and crashed with AttributeError: 'int' object has no attribute 'strip'. We observed the integer-code error body coming from api.openai.com itself (a one-off during a burst of concurrent chat completions), and OpenAI-compatible gateways/servers return integer codes routinely.
Suggested fix: either coerce non-None values to str when constructing the exception, or widen the annotation so type checkers tell consumers the truth.
To Reproduce
The value flows through construct_type unvalidated:
from typing import Optional
from openai._models import construct_type
value = construct_type(type_=Optional[str], value=404)
print(type(value)) # <class 'int'> — despite the Optional[str] target
End to end: point the client at any server whose error body contains "code": 404 (integer), catch the raised APIStatusError, and inspect exc.code.
Code snippets
import openai
client = openai.OpenAI(api_key="test", base_url="http://localhost:9999/v1")
# server responds 404 with body: {"error": {"message": "nope", "type": "invalid_request_error", "code": 404}}
try:
client.chat.completions.create(model="gpt-4.1", messages=[{"role": "user", "content": "hi"}])
except openai.APIStatusError as exc:
reveal_type(exc.code) # type checker: str | None
print(type(exc.code)) # runtime: <class 'int'>
OS
macOS / Linux
Python version
Python 3.14.6
Library version
openai v2.46.0
Confirm this is an issue with the Python library and not an underlying OpenAI API
Describe the bug
APIStatusError.codeis annotatedOptional[str], but at runtime it can hold anint(or any other JSON type the server puts inerror.code).In
openai/_exceptions.pythe field is built with the lenient deserializer and an explicitcast(Any, ...):construct_typereturns the value unchanged when it doesn't match the target type — it neither coerces nor rejects — and thecast(Any, ...)suppresses the type checker, so nothing ever enforces theOptional[str]annotation. When an error body contains a JSON number ({"error": {"code": 404, ...}}),exc.codeis anint.This bit us in production: downstream code that trusted the annotation called
exc.code.strip()and crashed withAttributeError: 'int' object has no attribute 'strip'. We observed the integer-code error body coming from api.openai.com itself (a one-off during a burst of concurrent chat completions), and OpenAI-compatible gateways/servers return integer codes routinely.Suggested fix: either coerce non-
Nonevalues tostrwhen constructing the exception, or widen the annotation so type checkers tell consumers the truth.To Reproduce
The value flows through
construct_typeunvalidated:End to end: point the client at any server whose error body contains
"code": 404(integer), catch the raisedAPIStatusError, and inspectexc.code.Code snippets
OS
macOS / Linux
Python version
Python 3.14.6
Library version
openai v2.46.0