Skip to content

fix(client): narrow retry exception handling to transport errors#2956

Open
mvanhorn wants to merge 2 commits intoopenai:mainfrom
mvanhorn:osc/2737-narrow-retry-exception-handling
Open

fix(client): narrow retry exception handling to transport errors#2956
mvanhorn wants to merge 2 commits intoopenai:mainfrom
mvanhorn:osc/2737-narrow-retry-exception-handling

Conversation

@mvanhorn
Copy link

Summary

  • Narrows except Exception in both sync and async retry loops to except (httpx.TransportError, OSError), so only network/transport failures trigger retries
  • Fixes issue where application-level exceptions (e.g. Celery's SoftTimeLimitExceeded) were caught and retried instead of propagating

Fixes #2737

Details

The retry logic in SyncAPIClient._retry_request and AsyncAPIClient._retry_request previously caught bare Exception. This meant any non-APITimeoutError exception - including framework signals like Celery's SoftTimeLimitExceeded or KeyboardInterrupt subclasses - would be caught and retried up to max_retries times before re-raising.

httpx.TransportError is the base class for all httpx transport-level errors (connection failures, read errors, etc.), and OSError covers low-level socket errors that may not be wrapped by httpx. Together they cover the full set of retriable network failures without catching application-level exceptions.

Test plan

  • All 49 existing retry tests pass (tests/test_client.py retry-related tests)
  • Verified exception hierarchy: httpx.TimeoutException is a subclass of httpx.TransportError (already handled separately as APITimeoutError)
  • Verified SoftTimeLimitExceeded (and similar non-network exceptions) are NOT subclasses of TransportError or OSError

This contribution was developed with AI assistance (Claude Code).

The retry loop previously caught `Exception`, which inadvertently
intercepted application-level exceptions like Celery's
`SoftTimeLimitExceeded`. Narrow the catch to `httpx.TransportError`
and `OSError`, which covers all network/transport failures while
allowing non-network exceptions to propagate immediately.

Fixes openai#2737

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 996810d560

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

raise APITimeoutError(request=request) from err
except Exception as err:
log.debug("Encountered Exception", exc_info=True)
except (httpx.TransportError, OSError) as err:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Catch remaining httpx request errors before re-raising

Narrowing this handler to httpx.TransportError/OSError lets other httpx.RequestError subclasses (for example TooManyRedirects when redirects loop, or DecodingError on malformed encoded bodies) escape as raw httpx exceptions from request() instead of being normalized to APIConnectionError. That is a behavior regression from the previous code path and can break callers that rely on the documented openai.APIError hierarchy for SDK failures.

Useful? React with 👍 / 👎.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch - widened to httpx.RequestError in c90c5cd which is the parent class of TransportError and also catches TooManyRedirects, DecodingError, and any other request-phase subclasses. Still narrower than the original except Exception but no longer misses legitimate httpx errors.

…errors

httpx.TransportError missed TooManyRedirects and DecodingError which are
also httpx.RequestError subclasses. Using RequestError catches all
request-phase failures while still excluding unrelated exceptions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

OpenAI client intercepts Celery SoftTimeLimitExceeded exception if it happens during API call

1 participant