Skip to content

fix(agents): catch Anthropic RateLimitError in ChatAgent retry loop - #4140

Open
RajanChavada wants to merge 4 commits into
camel-ai:masterfrom
RajanChavada:fix/rate-limit-error-non-openai-models
Open

fix(agents): catch Anthropic RateLimitError in ChatAgent retry loop#4140
RajanChavada wants to merge 4 commits into
camel-ai:masterfrom
RajanChavada:fix/rate-limit-error-non-openai-models

Conversation

@RajanChavada

Copy link
Copy Markdown

Related Issue

Closes #3882

Description

Problem

ChatAgent._get_model_response and _aget_model_response retry on rate-limit errors using exponential backoff. The except clause imported RateLimitError exclusively from the openai package:

from openai import RateLimitError
...
except RateLimitError as e:   # only catches openai's exception class

When a user runs ChatAgent with AnthropicModel, a 429 response from the Anthropic API raises anthropic.RateLimitError — a completely separate class with no shared base. The retry loop never fires, and the error propagates uncaught to the caller as an unhandled exception, crashing the agent instead of retrying.

Fix

Introduce _RATE_LIMIT_ERRORS, a tuple built at import time from every provider rate-limit exception that is installed in the current environment:

try:
    from anthropic import RateLimitError as AnthropicRateLimitError
except ImportError:
    AnthropicRateLimitError = None

_RATE_LIMIT_ERRORS: tuple = tuple(
    e for e in [RateLimitError, AnthropicRateLimitError] if e is not None
)

Both except clauses now catch _RATE_LIMIT_ERRORS instead of the bare RateLimitError. The anthropic package is already an optional dependency in pyproject.toml — no new dependencies added.

What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

Changes Made

File Change
camel/agents/chat_agent.py Optional import of anthropic.RateLimitError; build _RATE_LIMIT_ERRORS tuple; swap both except RateLimitError clauses
test/agents/test_chat_agent.py Two new unit tests: one verifies openai.RateLimitError triggers the retry loop; one verifies anthropic.RateLimitError is included in the tuple when the package is installed

Net diff: +14 lines production code, +41 test lines.

Testing Done

OPENAI_API_KEY=sk-test python -m pytest \
  test/agents/test_chat_agent.py::test_rate_limit_retry_on_openai_rate_limit_error \
  test/agents/test_chat_agent.py::test_rate_limit_retry_respects_anthropic_error_when_installed \
  -v
PASSED test_rate_limit_retry_on_openai_rate_limit_error
PASSED test_rate_limit_retry_respects_anthropic_error_when_installed
2 passed in 0.79s
  • test_rate_limit_retry_on_openai_rate_limit_error: mocks model_backend.run to always raise openai.RateLimitError, asserts run is called exactly retry_attempts (3) times before the final exception is raised.
  • test_rate_limit_retry_respects_anthropic_error_when_installed: asserts anthropic.RateLimitError is present in _RATE_LIMIT_ERRORS when the anthropic package is installed, and gracefully skips otherwise.

Checklist

  • I have read and agree to the AI-Generated Code Policy (required)
  • I have linked this PR to an issue (required)
  • I have checked if any dependencies need to be added or updated in pyproject.toml and run uv lock — no new deps; anthropic is already optional
  • I have updated the tests accordingly
  • I have updated the documentation if needed
  • I have added examples if this is a new feature

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

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: e4e5a743-a2be-4acf-8a37-393652155626

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.

Fixes camel-ai#3882

The retry logic in `_get_model_response` and `_aget_model_response`
imported `RateLimitError` exclusively from the `openai` package. When
using `AnthropicModel`, a rate-limit response raises
`anthropic.RateLimitError` instead, which bypassed the retry loop
entirely and surfaced as an unhandled exception to the caller.

Introduce `_RATE_LIMIT_ERRORS`, a tuple assembled at import time from
whichever provider SDKs are installed (openai always present,
anthropic optional). Both `except` clauses now catch the full tuple,
so retry-with-backoff works for Anthropic models without adding a hard
dependency on the anthropic package.
@RajanChavada
RajanChavada force-pushed the fix/rate-limit-error-non-openai-models branch from 1b30182 to 2a3c98d Compare July 2, 2026 01:19
@RajanChavada

Copy link
Copy Markdown
Author

Tagging @fengju0213 @maoxin1234: would appreciate a review when you get a chance! This fixes #3882 (Anthropic
RateLimitError bypassing the retry loop). Small change, 2 files.

RajanChavada and others added 3 commits July 1, 2026 22:09
Use specific ModelProcessingError instead of bare Exception in
pytest.raises, satisfying ruff B017. Apply ruff-format style changes
to existing test assertions (line-wrap style only, no logic changes).
@AmirF194

AmirF194 commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Nice, targeted fix and the root cause is right: the retry loop only caught openai.RateLimitError, so Anthropic's RateLimitError (a separate class with no shared base) skipped the backoff and re-raised through the generic handler.

The important part is handled well. The anthropic import is guarded with try/except ImportError and the tuple filters out the None fallback, so environments without the optional package still work and just get (RateLimitError,). Catching a narrow tuple ahead of except Exception also means you are not at risk of retrying unrelated errors, which I prefer over the broader except Exception + 429-heuristic approach in some of the sibling PRs.

Non-blocking suggestions:

  • The Anthropic test only asserts membership in _RATE_LIMIT_ERRORS; it never runs an anthropic.RateLimitError through the loop. Since the OpenAI test already drives the loop cleanly, parametrizing it over both classes would actually cover the bug path this PR fixes.
  • Scope is OpenAI + Anthropic only. A 429 from Mistral / Google GenAI still will not retry. Fine to leave for a follow-up, but worth noting that fix: generalize rate-limit retry to all model providers #3974 solves the general case with a reusable is_rate_limit_error() util if maintainers want provider-agnostic coverage.

CI is red only from the fork-secrets collection errors (missing OPENAI_API_KEY across unrelated test files), not from anything in this change.

Coordination note: this overlaps with #3949, #3958, and #3974, which all target the same issue. Of that set this one is the most mergeable for the specific reported bug (guarded import plus real tests). Might be worth flagging to maintainers to avoid splitting the effort.

@RajanChavada

RajanChavada commented Jul 9, 2026

Copy link
Copy Markdown
Author

Flagging @lightaime @fengju0213 to take a look to avoid unnecessary developer overlap

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