Skip to content

Fix responses.parse() memory leak from runtime generic schema rebuilds#3092

Open
erhan1209 wants to merge 1 commit intoopenai:mainfrom
erhan1209:fix/responses-parse-memory-leak-3084
Open

Fix responses.parse() memory leak from runtime generic schema rebuilds#3092
erhan1209 wants to merge 1 commit intoopenai:mainfrom
erhan1209:fix/responses-parse-memory-leak-3084

Conversation

@erhan1209
Copy link
Copy Markdown

  • I understand that this repository is auto-generated and my pull request may not be merged

Changes being requested

Fix issue #3084 in responses.parse().

The parser was constructing parameterized generic response models at runtime:

  • ParsedResponseOutputText[TextFormatT]
  • ParsedResponseOutputMessage[TextFormatT]
  • ParsedResponse[TextFormatT]

With Pydantic v2, feeding unresolved generics into runtime construction can trigger repeated schema rebuilds instead of stable reuse, which can cause memory growth in long-running processes using responses.parse().

This change switches runtime construction in src/openai/lib/_parsing/_responses.py to the non-parameterized classes:

  • ParsedResponseOutputText
  • ParsedResponseOutputMessage
  • ParsedResponse

The generic return typing is preserved with cast(...), so the static typing behavior remains unchanged.

A regression test was added to verify that parse_response() only passes non-parameterized runtime response types into construct_type_unchecked.

Additional context & links

Fixes #3084

Verification:

  • $env:PYTHONPATH='src'; python -m pytest -q tests/lib/responses/test_responses.py -n 0
  • $env:PYTHONPATH='src'; python -m pytest -q tests/test_models.py tests/test_response.py -n 0

## Summary
This fixes issue `openai#3084`.

`responses.parse()` was constructing parameterized generic response models at runtime:
- `ParsedResponseOutputText[TextFormatT]`
- `ParsedResponseOutputMessage[TextFormatT]`
- `ParsedResponse[TextFormatT]`

Those unresolved generics can cause Pydantic to repeatedly rebuild schemas instead of reusing them, which leads to memory growth in long-running processes.

## What changed
- Switched runtime construction in `src/openai/lib/_parsing/_responses.py` to use the non-parameterized classes:
  - `ParsedResponseOutputText`
  - `ParsedResponseOutputMessage`
  - `ParsedResponse`
- Kept the generic return typing via `cast(...)`, so the public type experience stays the same.
- Added a regression test to verify `parse_response()` only passes non-parameterized runtime response types into `construct_type_unchecked`.

## Why this is safe
The generic parameter is only needed for static typing here. At runtime, the parsed response models already use non-parameterized field definitions outside `TYPE_CHECKING`, so constructing the base classes preserves behavior while avoiding repeated schema rebuilds.

## Verification
Ran:
- `$env:PYTHONPATH='src'; python -m pytest -q tests/lib/responses/test_responses.py -n 0`
- `$env:PYTHONPATH='src'; python -m pytest -q tests/test_models.py tests/test_response.py -n 0`
@erhan1209 erhan1209 requested a review from a team as a code owner April 15, 2026 14:27
@erhan1209 erhan1209 requested a review from afurm April 15, 2026 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Async Responses Structured Outputs Memory leak

2 participants