Skip to content

APIStatusError.code is typed Optional[str] but can be an int at runtime #3531

Description

@emiliyanpavlov

Confirm this is an issue with the Python library and not an underlying OpenAI API

  • This is an issue with the Python library

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions