Skip to content

Add automatic retry logic for transient Gemini API errors (503, 429) - #385

Merged
aksg87 merged 3 commits into
google:mainfrom
YuqiGuo105:fix/chunk-retry-503
Apr 21, 2026
Merged

aksg87 merged 3 commits into
google:mainfrom
YuqiGuo105:fix/chunk-retry-503

Conversation

@YuqiGuo105

@YuqiGuo105 YuqiGuo105 commented Feb 20, 2026 •

Copy link
Copy Markdown
Contributor

Description

Fixes #240

This change implements exponential backoff retry for transient errors in the Gemini provider, preventing entire document processing failures when a single chunk encounters temporary service overload (503) or rate limiting (429) errors.

Changes:

  • Add retry configuration parameters (max_retries, retry_delay, max_retry_delay)
  • Implement _is_retryable_error() to distinguish temporary vs permanent errors
  • Add exponential backoff retry logic in _process_single_prompt()
  • Each chunk retries independently without affecting other chunks
  • Add comprehensive test coverage (30 test cases)

How Has This Been Tested?

Test suite in tests/test_gemini_retry.py with 30 test cases covering error classification, retry logic, parallel processing, and configuration.

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective
  • New and existing unit tests pass locally with my changes

@google-cla

google-cla Bot commented Feb 20, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@github-actions github-actions Bot added the size/L Pull request with 600-1000 lines changed label Feb 20, 2026
@YuqiGuo105
YuqiGuo105 force-pushed the fix/chunk-retry-503 branch 3 times, most recently from 65139a1 to 5152918 Compare February 22, 2026 08:16
@github-actions

Copy link
Copy Markdown

⚠️ Branch Update Required

Your branch is 1 commits behind main. Please update your branch to ensure CI checks run with the latest code:

git fetch origin main
git merge origin/main
git push

Note: Enable "Allow edits by maintainers" to allow automatic updates.

1 similar comment
@github-actions

Copy link
Copy Markdown

⚠️ Branch Update Required

Your branch is 1 commits behind main. Please update your branch to ensure CI checks run with the latest code:

git fetch origin main
git merge origin/main
git push

Note: Enable "Allow edits by maintainers" to allow automatic updates.

@github-actions

Copy link
Copy Markdown

⚠️ Branch Update Required

Your branch is 6 commits behind main. Please update your branch to ensure CI checks run with the latest code:

git fetch origin main
git merge origin/main
git push

Note: Enable "Allow edits by maintainers" to allow automatic updates.

@github-actions

github-actions Bot commented Apr 5, 2026

Copy link
Copy Markdown

⚠️ Branch Update Required

Your branch is 8 commits behind main. Please update your branch to ensure CI checks run with the latest code:

git fetch origin main
git merge origin/main
git push

Note: Enable "Allow edits by maintainers" to allow automatic updates.

@github-actions

Copy link
Copy Markdown

⚠️ Branch Update Required

Your branch is 11 commits behind main. Please update your branch to ensure CI checks run with the latest code:

git fetch origin main
git merge origin/main
git push

Note: Enable "Allow edits by maintainers" to allow automatic updates.

@github-actions

Copy link
Copy Markdown

⚠️ Branch Update Required

Your branch is 15 commits behind main. Please update your branch to ensure CI checks run with the latest code:

git fetch origin main
git merge origin/main
git push

Note: Enable "Allow edits by maintainers" to allow automatic updates.

Fixes google#240

This change implements exponential backoff retry for transient errors
in the Gemini provider, preventing entire document processing failures
when a single chunk encounters temporary service overload (503) or rate
limiting (429) errors.

Changes:
- Add retry configuration parameters (max_retries, retry_delay, max_retry_delay)
- Implement _is_retryable_error() to distinguish temporary vs permanent errors
- Add exponential backoff retry logic in _process_single_prompt()
- Each chunk retries independently without affecting other chunks
- Add comprehensive test coverage (30 test cases)

Benefits:
- Prevents API quota waste from re-processing entire documents
- Reduces 429 errors from excessive retries
- Improves reliability for large batch processing
aksg87 added a commit to YuqiGuo105/langextract that referenced this pull request Apr 21, 2026
Maintainer polish on top of google#385:

- Typed google.genai APIError.code classification for 408/429/5xx; fall
  through to httpx transient subclasses (TimeoutException, NetworkError,
  RemoteProtocolError, ProxyError) and stdlib ConnectionError/TimeoutError.
  LocalProtocolError and UnsupportedProtocol intentionally excluded since
  they indicate client/config bugs.
- Narrow regex fallback for exceptions that only carry the status in a
  message; avoids matching permanent failures like bare "quota" or
  "unavailable".
- Multiplicative jitter (uniform(0.5, 1.5)) with post-jitter cap at
  max_retry_delay so the named maximum bounds the real sleep.
- Keyword-only retry knobs (max_retries, retry_delay, max_retry_delay)
  with init-time validation.
- Guard against stacking with google-genai HttpOptions.retry_options.
  Matches the SDK's own normalization: retry_options with attempts in
  {0, 1} is treated as "retries disabled" and allowed; None or >1 raises
  InferenceConfigError. Covers HttpOptions object, HttpOptionsDict
  snake-case, and HttpOptionsDict camelCase shapes.
- Rename tests/test_gemini_retry.py -> tests/gemini_retry_test.py to match
  the repo's pytest discovery pattern (python_files = "*_test.py").
- 65 parametrized tests (absl.testing.parameterized) covering the
  classifier, retry loop, parallel-chunk scenarios, init validation, and
  the SDK stacking guard matrix.
@aksg87
aksg87 force-pushed the fix/chunk-retry-503 branch from 55e2fdd to eb4dda3 Compare April 21, 2026 01:15
@github-actions github-actions Bot added size/M Pull request with 150-600 lines changed and removed size/L Pull request with 600-1000 lines changed labels Apr 21, 2026
Maintainer polish on top of google#385:

- Typed google.genai APIError.code classification for 408/429/5xx; fall
  through to httpx transient subclasses (TimeoutException, NetworkError,
  RemoteProtocolError, ProxyError) and stdlib ConnectionError/TimeoutError.
  LocalProtocolError and UnsupportedProtocol intentionally excluded since
  they indicate client/config bugs.
- Narrow regex fallback for exceptions that only carry the status in a
  message; avoids matching permanent failures like bare "quota" or
  "unavailable".
- Multiplicative jitter (uniform(0.5, 1.5)) with post-jitter cap at
  max_retry_delay so the named maximum bounds the real sleep.
- Keyword-only retry knobs (max_retries, retry_delay, max_retry_delay)
  with init-time validation.
- Guard against stacking with google-genai HttpOptions.retry_options.
  Matches the SDK's own normalization: retry_options with attempts in
  {0, 1} is treated as "retries disabled" and allowed; None or >1 raises
  InferenceConfigError. Covers HttpOptions object, HttpOptionsDict
  snake-case, and HttpOptionsDict camelCase shapes.
- Rename tests/test_gemini_retry.py -> tests/gemini_retry_test.py to match
  the repo's pytest discovery pattern (python_files = "*_test.py").
- 65 parametrized tests (absl.testing.parameterized) covering the
  classifier, retry loop, parallel-chunk scenarios, init validation, and
  the SDK stacking guard matrix.
@aksg87
aksg87 force-pushed the fix/chunk-retry-503 branch from eb4dda3 to 7e5f7ba Compare April 21, 2026 02:12
@github-actions github-actions Bot added size/L Pull request with 600-1000 lines changed and removed size/M Pull request with 150-600 lines changed labels Apr 21, 2026
@aksg87 aksg87 added the ready-to-merge Triggers live API tests for PRs from forks label Apr 21, 2026
@aksg87 aksg87 added ready-to-merge Triggers live API tests for PRs from forks and removed ready-to-merge Triggers live API tests for PRs from forks labels Apr 21, 2026
@aksg87
aksg87 merged commit 3aab86c into google:main Apr 21, 2026
14 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Triggers live API tests for PRs from forks size/L Pull request with 600-1000 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

langextract chunking does not recover from 503 error "The model is overloaded"

2 participants