Background responses failures lack a stable code/name that maps to an exception class
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 31.6k
- Forks
- 5.7k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 96
Description
Confirm this is a feature request for the Python library and not the underlying OpenAI API.
- This is a feature request for the Python library
Describe the feature or improvement you're requesting
When the Responses API runs in background mode (background=True) and a run terminates in status="failed" (or status="incomplete"), the SDK does not surface a stable, machine-readable identifier that callers can map to an existing exception class.
The failure payload looks like:
{
"status": "failed",
"error": { "code": "server_error", "message": "..." },
"incomplete_details": null
}
The HTTP poll itself returns 200 OK, so the SDK's status-code dispatcher is never invoked and no typed exception is raised. The only signal of what kind of failure occurred is the free-form error.code string, which:
- is not documented as a stable enum,
- does not correspond 1:1 to any SDK exception class (
server_error≠InternalServerError,rate_limit_exceeded≠RateLimitError, etc.), - is not guaranteed to be present or non-null for every failure mode (e.g.
incompleteruns surface their reason inincomplete_details.reasoninstead, with yet another vocabulary), - and may carry values not enumerated anywhere the SDK or callers can rely on.
What exists today (synchronous mode)
For synchronous calls there is a clean, code-driven mapping in openai/_client.py keyed on HTTP status code:
def _make_status_error(self, err_msg, *, body, response):
data = body.get("error", body) if is_mapping(body) else body
if response.status_code == 400: return BadRequestError(...)
if response.status_code == 401: return AuthenticationError(...)
if response.status_code == 403: return PermissionDeniedError(...)
if response.status_code == 404: return NotFoundError(...)
if response.status_code == 409: return ConflictError(...)
if response.status_code == 422: return UnprocessableEntityError(...)
if response.status_code == 429: return RateLimitError(...)
if response.status_code >= 500: return InternalServerError(...)
return APIStatusError(...)
So the synchronous path has a fully deterministic, documented contract: HTTP code → exception class. The background path has no equivalent — neither in the response body (no stable code) nor in the SDK (no dispatcher).
Why this matters
In synchronous mode the SDK gives us a clean contract. In background mode the same root cause surfaces only as an opaque string with no contract. Any retry/backoff logic built around isinstance(e, InternalServerError) or isinstance(e, RateLimitError) simply cannot work for background runs, even though those are exactly the conditions where retry would be most useful.
Suggested feature
Either:
-
Add a stable, documented field to background-run failure payloads (e.g.
error.typeorerror.class) whose values directly correspond to existing SDK exception classes — e.g.internal_server_error,rate_limit_error,bad_request_error,content_filter_error, etc. The SDK can then mechanically map this field to the right exception class, mirroring what_make_status_errordoes today for HTTP status codes. -
Or: publish a documented, versioned mapping from each possible
error.code/incomplete_details.reasonvalue to the SDK exception class (or "no class") and to a retryable flag. Treat it as part of the public API contract.
Either approach gives background runs the same deterministic contract synchronous calls already enjoy.
Environment
openaiPython SDK version:<fill in>- API:
POST /v1/responseswithbackground=true, polled viaGET /v1/responses/{id}
Additional context
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with openai/_client.py and its _make_status_error method, then trace polling for POST /v1/responses with background=true via GET /v1/responses/{id}. Compare the synchronous HTTP-status mapping with failed and incomplete response handling. Done means the chosen stable mapping or documented contract covers these background outcomes and their retryability.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100