openclaw - 💡(How to fix) Fix [Bug]: Google API 429 Rate Limits are swallowed and misclassified as timeouts due to regex and idle timer race condition [1 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Instead of registering a 429 from a google provider when a rate limit has been reached and triggering a cool down limit to switch to a new provider, google provider calls simply timeout and new requests retry the same provider

Error Message

2026-05-14T03:29:40.869Z warn agent/embedded {"subsystem":"agent/embedded"} {"event":"embedded_run_failover_decision","tags":["error_handling","failover","assistant","rotate_profile"],"runId":"330507c9-1b51-42cf-920c-9ae6a6f3e017","stage":"assistant","decision":"rotate_profile","failoverReason":"timeout","profileFailureReason":"timeout","provider":"google","model":"gemini-3-flash-preview","sourceProvider":"google","sourceModel":"gemini-3-flash-preview","profileId":"sha256:87f86facc92d","fallbackConfigured":false,"timedOut":true,"aborted":true} embedded run failover decision2026-05-14T03:29:57.062Z warn agent/embedded {"subsystem":"agent/embedded"} Profile google:TEST timed out. Trying next account...2026-05-14T03:29:57.065Z warn agent/embedded {"subsystem":"agent/embedded"} {"event":"embedded_run_failover_decision","tags":["error_handling","failover","assistant","rotate_profile"],"runId":"330507c9-1b51-42cf-920c-9ae6a6f3e017","stage":"assistant","decision":"rotate_profile","failoverReason":"timeout","profileFailureReason":"timeout","provider":"google","model":"gemini-3-flash-preview","sourceProvider":"google","sourceModel":"gemini-3-flash-preview","profileId":"sha256:ab078ebc96c2","fallbackConfigured":false,"timedOut":true,"aborted":true} embedded run failover decision There are two interacting bugs in the error handling pipeline that cause the 429 status to be lost: Furthermore, the regex expects the HTTP status code at the beginning of the string, but the Google API returns it in parentheses: "Google Generative AI API error (429): Resource has been exhausted". Because timedOut is true, the reason is hardcoded to "timeout", entirely discarding the actual 429 error payload. In handleAssistantFailover, check the params.lastAssistant.errorMessage for "429" or "exhausted" before falling back to the "timeout" string. If the raw error message indicates a rate limit, the reason should be set to "rate_limit" even if the idle timer triggered.

Root Cause

Root Cause Analysis:

Fix Action

Fixed

Code Example

2026-05-14T03:29:40.869Z warn agent/embedded {"subsystem":"agent/embedded"} {"event":"embedded_run_failover_decision","tags":["error_handling","failover","assistant","rotate_profile"],"runId":"330507c9-1b51-42cf-920c-9ae6a6f3e017","stage":"assistant","decision":"rotate_profile","failoverReason":"timeout","profileFailureReason":"timeout","provider":"google","model":"gemini-3-flash-preview","sourceProvider":"google","sourceModel":"gemini-3-flash-preview","profileId":"sha256:87f86facc92d","fallbackConfigured":false,"timedOut":true,"aborted":true} embedded run failover decision2026-05-14T03:29:57.062Z warn agent/embedded {"subsystem":"agent/embedded"} Profile google:TEST timed out. Trying next account...2026-05-14T03:29:57.065Z warn agent/embedded {"subsystem":"agent/embedded"} {"event":"embedded_run_failover_decision","tags":["error_handling","failover","assistant","rotate_profile"],"runId":"330507c9-1b51-42cf-920c-9ae6a6f3e017","stage":"assistant","decision":"rotate_profile","failoverReason":"timeout","profileFailureReason":"timeout","provider":"google","model":"gemini-3-flash-preview","sourceProvider":"google","sourceModel":"gemini-3-flash-preview","profileId":"sha256:ab078ebc96c2","fallbackConfigured":false,"timedOut":true,"aborted":true} embedded run failover decision
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

Instead of registering a 429 from a google provider when a rate limit has been reached and triggering a cool down limit to switch to a new provider, google provider calls simply timeout and new requests retry the same provider

Steps to reproduce

  1. openclaw models auth add (type in google)
  2. use up a limit of a model (say gemini flash)
  3. make a new request waiting for the backup auth provider to takeover
  4. Every new request will try the first auth provider and timeout before making a successful call. You can see it in the logs with cli running openclaw logs --follow

Expected behavior

after a failed request to google the auth provider should trigger openclaws cooldown but this does not happen

Actual behavior

the backup provider will only be used after the default provider times out. For EVERY request. No cooldown is triggered.

OpenClaw version

2026.5.7

Operating system

Ubuntu 24.04.4

Install method

npm global

Model

gemma-4-31b-it

Provider / routing chain

google -> google 2

Additional provider/model setup details

openclaw models auth add -> google x2

Logs, screenshots, and evidence

2026-05-14T03:29:40.869Z warn agent/embedded {"subsystem":"agent/embedded"} {"event":"embedded_run_failover_decision","tags":["error_handling","failover","assistant","rotate_profile"],"runId":"330507c9-1b51-42cf-920c-9ae6a6f3e017","stage":"assistant","decision":"rotate_profile","failoverReason":"timeout","profileFailureReason":"timeout","provider":"google","model":"gemini-3-flash-preview","sourceProvider":"google","sourceModel":"gemini-3-flash-preview","profileId":"sha256:87f86facc92d","fallbackConfigured":false,"timedOut":true,"aborted":true} embedded run failover decision2026-05-14T03:29:57.062Z warn agent/embedded {"subsystem":"agent/embedded"} Profile google:TEST timed out. Trying next account...2026-05-14T03:29:57.065Z warn agent/embedded {"subsystem":"agent/embedded"} {"event":"embedded_run_failover_decision","tags":["error_handling","failover","assistant","rotate_profile"],"runId":"330507c9-1b51-42cf-920c-9ae6a6f3e017","stage":"assistant","decision":"rotate_profile","failoverReason":"timeout","profileFailureReason":"timeout","provider":"google","model":"gemini-3-flash-preview","sourceProvider":"google","sourceModel":"gemini-3-flash-preview","profileId":"sha256:ab078ebc96c2","fallbackConfigured":false,"timedOut":true,"aborted":true} embedded run failover decision

Impact and severity

Moderate. Anyone using multiple auth providers for google.

Additional information

Kimik 2.6 found the following evidence:

Root Cause Analysis:

There are two interacting bugs in the error handling pipeline that cause the 429 status to be lost:

  1. Regex Minification/Formatting Bug In errors.js (compiled to errors-BqFqz2qx.js), the extractLeadingHttpStatus function contains a broken regex: (?:https*)?. It appears a backslash was lost during minification/bundling, and it should likely be (?:http\s*)?. Furthermore, the regex expects the HTTP status code at the beginning of the string, but the Google API returns it in parentheses: "Google Generative AI API error (429): Resource has been exhausted".

  2. The Idle Timeout Override Even if the regex matched, the idle timeout (from resolveLlmIdleTimeoutMs) often fires before the 429 response is fully processed. This causes the attempt to abort with timedOut: true. In handleAssistantFailover (inside pi-embedded), the code does this: JavaScript

const reason = params.timedOut ? "timeout" : params.assistantProfileFailureReason;

Because timedOut is true, the reason is hardcoded to "timeout", entirely discarding the actual 429 error payload.

Finally, maybeMarkAuthProfileFailure explicitly skips cooldowns if the reason is "timeout" (if (reason === "timeout") return;), causing the rate limit to be completely ignored. Suggested Fix:

Update extractLeadingHttpStatus to correctly parse status codes inside parentheses (e.g., /\((\d{3})\)/).

In handleAssistantFailover, check the params.lastAssistant.errorMessage for "429" or "exhausted" before falling back to the "timeout" string. If the raw error message indicates a rate limit, the reason should be set to "rate_limit" even if the idle timer triggered.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

after a failed request to google the auth provider should trigger openclaws cooldown but this does not happen

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Bug]: Google API 429 Rate Limits are swallowed and misclassified as timeouts due to regex and idle timer race condition [1 pull requests]