Skip to content

fix: generalize rate-limit retry to all model providers#3974

Open
4444J99 wants to merge 2 commits intocamel-ai:masterfrom
4444J99:fix/generalize-rate-limit-error-handling
Open

fix: generalize rate-limit retry to all model providers#3974
4444J99 wants to merge 2 commits intocamel-ai:masterfrom
4444J99:fix/generalize-rate-limit-error-handling

Conversation

@4444J99
Copy link
Copy Markdown

@4444J99 4444J99 commented Mar 27, 2026

Description

Resolves #3882.

ChatAgent._get_model_response and _aget_model_response catch only openai.RateLimitError, so rate-limit responses from Anthropic, Google GenAI, Mistral, and other providers bypass the retry logic entirely — the error falls through to the generic except Exception block and raises immediately instead of backing off and retrying.

Changes

camel/utils/commons.py

Added is_rate_limit_error(error) — a provider-agnostic utility that detects HTTP 429 rate-limit errors from any supported model backend:

  1. OpenAIopenai.RateLimitError
  2. Anthropicanthropic.RateLimitError
  3. Google GenAIgoogle.genai.errors.ClientError with code == 429
  4. Mistralmistralai.models.sdkerror.SDKError with status_code == 429
  5. Class-name heuristic — any exception named RateLimitError (forward-compatible with new SDKs)
  6. Generic fallback — any exception with status_code == 429

Each provider check uses a lazy try/except ImportError so only installed SDKs are inspected, with zero import-time overhead when a provider is not in use.

camel/agents/chat_agent.py

  • Removed the direct from openai import RateLimitError import
  • Both sync and async retry loops now catch Exception and dispatch via is_rate_limit_error(e) — rate-limit errors trigger exponential backoff with jitter; all other errors re-raise immediately (preserving existing behavior)

camel/utils/__init__.py

  • Exported is_rate_limit_error in the public API

test/utils/test_commons.py

Added 6 unit tests covering:

  • OpenAI RateLimitError detection
  • Generic exceptions (negative case)
  • status_code=429 attribute (positive)
  • status_code=500 attribute (negative)
  • Class-name heuristic for unknown SDKs
  • Plain RuntimeError (negative)

Testing

All new tests pass locally. No existing tests were modified (only a new import added).

Replace the OpenAI-specific `RateLimitError` catch in
`ChatAgent._get_model_response` and `_aget_model_response` with a
provider-agnostic `is_rate_limit_error()` utility that detects 429
errors from OpenAI, Anthropic, Google GenAI, Mistral, and any SDK
exposing a `status_code` attribute or a `RateLimitError` class name.

Closes camel-ai#3882
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 38c9bc30-63f4-4e08-a405-02d512b5d69d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Wendong-Fan
Copy link
Copy Markdown
Member

@claude review

Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

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

⚠️ Code review skipped — your organization's overage spend limit has been reached.

Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.

Once credits are available, comment @claude review on this pull request to trigger a review.

Comment thread camel/utils/commons.py Outdated
status = getattr(error, "code", None) or getattr(
error, "status_code", None
)
if status == 429:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

i think 429 doesn't always mean rate limit, the check here is not robust

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed — status-code-only checks for Google GenAI, Mistral, and the generic fallback now require corroborating evidence (Retry-After header, X-RateLimit-Remaining: 0, or rate-limit keywords in the error message) before returning True; typed SDK exceptions remain as-is since their semantics are guaranteed.

A bare HTTP 429 status code is not always a rate limit — some
providers reuse it for quota exhaustion, concurrent-request caps,
or other throttling conditions.  The status-code-based fallback
paths (Google GenAI, Mistral, generic) now require at least one
corroborating signal: a Retry-After header, X-RateLimit-Remaining
at zero, or rate-limit keywords in the error message.

Typed SDK exceptions (openai.RateLimitError, anthropic.RateLimitError)
remain unchanged — their semantics are guaranteed by the SDK.

Co-Authored-By: Claude Opus 4.6 (1M context) <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.

[BUG] RateLimitError not generalizable

2 participants