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

  1. Retry with exponential backoff on ModelRateLimitError; DeepSeek 429s are frequently transient congestion
  2. Serialize or limit concurrent agents per key
  3. Shift heavy runs out of peak congestion windows when DeepSeek announces throttling
  4. 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

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


AI-assisted analysis of browser-use/browser-use@6c73fced2f (2026-08-14). Data as JSON: /api/errors/9c80da982297303d. Report an issue: GitHub.