browser-use/browser-use · warning · ModelRateLimitError
str(e)
Error message
str(e)
What it means
In ChatDeepSeek.ainvoke's plain-text path (no output_format and no tools), an openai.RateLimitError from client.chat.completions.create is re-raised as ModelRateLimitError with the SDK message. DeepSeek is called via the OpenAI-compatible SDK, so a 429 from api.deepseek.com is normalized into the library's retryable error type.
Source
Thrown at browser_use/llm/deepseek/chat.py:131
if ds_messages and isinstance(ds_messages[-1], dict) and ds_messages[-1].get('role') == 'assistant':
ds_messages[-1]['prefix'] = True
if stop:
common['stop'] = stop
# ① Regular multi-turn conversation/text output
if output_format is None and not tools:
try:
resp = await client.chat.completions.create( # type: ignore
model=self.model,
messages=ds_messages, # type: ignore
**common,
)
return ChatInvokeCompletion(
completion=resp.choices[0].message.content or '',
usage=None,
)
except RateLimitError as e:
raise ModelRateLimitError(str(e), model=self.name) from e
except (APIError, APIConnectionError, APITimeoutError, APIStatusError) as e:
raise ModelProviderError(str(e), model=self.name) from e
except Exception as e:
raise ModelProviderError(str(e), model=self.name) from e
# ② Function Calling path (with tools or output_format)
if tools or (output_format is not None and hasattr(output_format, 'model_json_schema')):
try:
call_tools = tools
tool_choice = None
if output_format is not None and hasattr(output_format, 'model_json_schema'):
tool_name = output_format.__name__
schema = SchemaOptimizer.create_optimized_json_schema(output_format)
schema.pop('title', None)
call_tools = [
{
'type': 'function',
'function': {View on GitHub (pinned to 6c73fced2f)
Solutions
- Retry with exponential backoff on ModelRateLimitError; DeepSeek 429s are frequently transient congestion
- Serialize or limit concurrent agents per key
- Shift heavy runs out of peak congestion windows when DeepSeek announces throttling
- Check balance/limits on the DeepSeek platform dashboard — sustained 429 can indicate a top-up or tier issue
Example fix
# before
history = await agent.run() # DEEPSEEK 429 mid-run
# after
async def run_retry(agent, n=5):
for i in range(n):
try:
return await agent.run()
except ModelRateLimitError:
if i == n - 1: raise
await asyncio.sleep(2 ** i) Defensive patterns
Strategy: retry
Try / catch
from browser_use.exceptions import ModelRateLimitError
async def deepseek_run(agent, attempts=5):
for i in range(attempts):
try:
return await agent.run()
except ModelRateLimitError:
if i == attempts - 1:
raise
await asyncio.sleep(min(120, 2 ** i)) # deepseek 429s can need longer windows Prevention
- Use longer backoff ceilings for DeepSeek — congestion-driven 429s resolve over minutes, not seconds
- Schedule heavy runs outside DeepSeek's announced throttling windows
- Keep per-key concurrency low; share load across keys only within ToS
When it happens
Trigger: Calling ainvoke with neither tools nor output_format while exceeding DeepSeek's per-key rate limits; concurrent agents sharing one DEEPSEEK_API_KEY; rapid step loops in browser automation; demand spikes on DeepSeek's service (their 429s also occur during regional congestion).
Common situations: DeepSeek free/discount时段 congestion (off-peak throttling is common and announced); parallel CI agents; aggressive retry loops without backoff amplifying request rate.
Related errors
- str(e)
- Rate limit exceeded. {error_detail}
- Failed to stop cloud browser: HTTP {response.status_code} -
- {error_message}
- {e.message}
AI-assisted analysis of browser-use/browser-use@6c73fced2f (2026-08-14).
Data as JSON: /api/errors/9c80da982297303d.
Report an issue: GitHub.