[429 Ratenlimit betrifft gesamten Google-Anbieter statt spezifisches Modell] - Google Gemini Provider: 429 Rate Limit Scopes to Entire Provider Instead of Specific Model
Wenn ein einzelnes Google Gemini-Modell das Ratenlimit (429) erreicht, wendet das OpenClaw-Gateway ein Backoff auf den gesamten 'google'-Anbieter an und blockiert so den Zugriff auf andere, unabhÀngige Modelle mit eigenen Kontingenten.
đ Symptome
Hauptmanifestation
Wenn ein bestimmtes Google Gemini-Modell sein Kontingent erschöpft hat, schlagen alle nachfolgenden Anfragen an jedes Modell unter dem google-Anbieter mit Ratenlimit-Fehlern fehl, selbst wenn diese Modelle unabhÀngige Kontingentzuweisungen haben.
Fehlerausgabe-Beispiele
Direkte API-Antwort (429 von Google):
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{
"error": {
"code": 429,
"message": "Resource has been exhausted (e.g. check quota).",
"status": "RESOURCE_EXHAUSTED"
}
}
OpenClaw Gateway-Antwort nach Backoff-Aktivierung:
{
"error": {
"type": "rate_limit_exceeded",
"provider": "google",
"message": "Provider 'google' is currently in cooldown due to rate limiting. Retry-After: 120s",
"retry_after": 120
}
}
Verhaltenssymptome
- Keine Modellisolierung: Der Wechsel von
gemini-3.1-pro-preview-customtoolszugemini-3.0-pro-previewstellt die FunktionalitĂ€t nicht wieder her. - Erweiterte NichtverfĂŒgbarkeit: Alle
google-Anbieter-Anfragen schlagen fehl, bis der Anbieter-Ebene-Cooldown ablÀuft. - Kein Fallback-Pfad: Alternative Modelle unter demselben Anbieter können wÀhrend von Ratenlimit-Ereignissen nicht als Fallbacks dienen.
- Gateway-Ebene-Ablehnung: Anfragen können auf der OpenClaw-Gateway-Ebene abgelehnt werden, bevor sie Googles API erreichen.
Reproduktionsszenario
# Step 1: Request to rate-limited model
curl -X POST https://api.openclaw.io/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "gemini-3.1-pro-preview-customtools", "messages": [{"role": "user", "content": "test"}]}'
# Response: 429 from Google API
# Step 2: Immediate fallback to another model
curl -X POST https://api.openclaw.io/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "gemini-3.0-pro-preview", "messages": [{"role": "user", "content": "test"}]}'
# Expected: Request proceeds to Google API
# Actual: 429 or backoff error from OpenClaw gateway
đ§ Ursache
Architekturanalyse
Die Ursache liegt in der anbieterbasierten Ratenlimit-Verfolgung-Implementierung innerhalb des Retry/Backoff-Mechanismus des OpenClaw-Gateways.
Fehlersequenz
- Anfrage an
gemini-3.1-pro-preview-customtools: Die modellspezifische Bereitstellung erhÀlt ein429 RESOURCE_EXHAUSTEDvon Googles API. - Gateway fÀngt 429 ab: OpenClaws Fehlerbehandlungs-Middleware fÀngt die 429-Antwort ab.
- Anbieter-Ebene-Backoff-Aktivierung: Anstatt das Ratenlimit gegen das spezifische Modell/die Bereitstellung zu erfassen, setzt das Gateway einen Cooldown-Timer auf den
google-Anbieterbezeichner. - Nachfolgende Anfrage an
gemini-3.0-pro-preview: Das Gateway prĂŒft, ob dergoogle-Anbieter im Cooldown ist. Da dies der Fall ist, lehnt es die Anfrage vorab mit einem Backoff-Fehler ab. - Modell mit unabhĂ€ngigem Kontingent wird blockiert:
gemini-3.0-pro-previewhat möglicherweise eine völlig separate Kontingentzuweisung, kann aber nicht zugegriffen werden.
Code-Ebene Ursache
Die Ratenlimit-Verfolgung verwendet wahrscheinlich eine Datenstruktur Àhnlich zu:
// Simplified representation of current behavior
const providerBackoff = {
"google": {
cooldownUntil: 1699999999999, // Unix timestamp
reason: "rate_limit",
retryAfter: 120
}
};
// Backoff check
function shouldReject(provider) {
return providerBackoff[provider]?.cooldownUntil > Date.now();
}
Das Problem: Der Backoff wird nach Anbieternamen (“google”) statt nach Modell- oder Bereitstellungsbezeichner verschlĂŒsselt.
Google Gemini API Kontingentarchitektur
Google Gemini API arbeitet mit:
- Modellspezifischen Kontingenten: Jedes Modell (z.B.
gemini-3.1-pro-preview-customtools) hat unabhÀngige Ratenlimits. - Projektbezogenen Kontingenten: Breitere Limits, die alle Modelle betreffen, aber diese sind typischerweise viel höher.
- Regionalen Endpunkten: Können unabhÀngige Limits haben.
Abweichende Codepfade
| Szenario | Aktuelles Verhalten | Erwartetes Verhalten |
|---|---|---|
| Modell A trifft 429 | Gesamter google-Anbieter blockiert | Nur Modell A blockiert |
| Modell A Kontingent erschöpft | Modell B unbrauchbar | Modell B fĂ€hrt fort, wenn Kontingent verfĂŒgbar |
| Anbieter-Backoff aktiv | Gateway lehnt auf Schicht 7 ab | Anfrage erreicht API |
đ ïž Schritt-fĂŒr-Schritt-Lösung
Option 1: Modellbezogene Ratenlimitierung aktivieren (Empfohlen)
Wenn OpenClaw die modellbezogene Ratenlimit-Verfolgung unterstĂŒtzt, konfigurieren Sie das Gateway fĂŒr modellbezogenen Backoff:
Vorher (openclaw.yaml):
providers:
google:
api_key: "${GOOGLE_API_KEY}"
rate_limit:
strategy: "provider" # Current: blocks entire provider
retry_after: 120
Nachher:
providers:
google:
api_key: "${GOOGLE_API_KEY}"
rate_limit:
strategy: "model" # Changed: per-model tracking
retry_after: 120
scope: "deployment" # Granularity: model/deployment level
Option 2: Modellspezifische Fallbacks konfigurieren
Definieren Sie explizite Fallback-Ketten, um ratenlimitierte Modelle zu umgehen:
Vorher:
models:
- name: "gemini-3.1-pro-preview-customtools"
provider: "google"
Nachher:
models:
- name: "gemini-3.1-pro-preview-customtools"
provider: "google"
fallback_models:
- "gemini-3.0-pro-preview"
- "gemini-pro"
- name: "gemini-3.0-pro-preview"
provider: "google"
fallback_models:
- "gemini-pro"
Option 3: Erhöhung der Anbieter-Cooldown-GranularitÀt (Code-Fix)
Wenn Sie Zugriff auf den OpenClaw-Quellcode haben, Àndern Sie die Ratenlimit-Verfolgung:
Schritt 1: Ratenlimit-Handler identifizieren
Locate the file handling 429 responses. Typically found at:
src/gateway/middleware/rate-limit-handler.ts
src/providers/google/error-handler.ts
Schritt 2: Backoff-SchlĂŒssel von Anbieter auf Modell Ă€ndern
// BEFORE (provider-level)
providerBackoff[provider] = {
cooldownUntil: Date.now() + retryAfter * 1000,
reason: "rate_limit"
};
// AFTER (model-level)
const modelKey = `${provider}:${model}`;
modelBackoff[modelKey] = {
cooldownUntil: Date.now() + retryAfter * 1000,
reason: "rate_limit",
model: model,
provider: provider
};
Schritt 3: Die AblehnungsprĂŒfung aktualisieren
// BEFORE
function shouldReject(request) {
const provider = request.provider;
return providerBackoff[provider]?.cooldownUntil > Date.now();
}
// AFTER
function shouldReject(request) {
const modelKey = `${request.provider}:${request.model}`;
const providerKey = request.provider;
// Check model-specific backoff first
if (modelBackoff[modelKey]?.cooldownUntil > Date.now()) {
return { rejected: true, reason: "model_rate_limited" };
}
// Fallback to provider-level for shared limits only
if (providerBackoff[providerKey]?.cooldownUntil > Date.now()) {
return { rejected: true, reason: "provider_rate_limited" };
}
return { rejected: false };
}
Option 4: Workaround ĂŒber mehrere Anbieterinstanzen
Erstellen Sie separate Anbieterkonfigurationen fĂŒr Modelle mit unabhĂ€ngigen Kontingenten:
providers:
google-gemini-31:
api_key: "${GOOGLE_API_KEY}"
models:
- "gemini-3.1-pro-preview-customtools"
rate_limit:
retry_after: 60
google-gemini-30:
api_key: "${GOOGLE_API_KEY}"
models:
- "gemini-3.0-pro-preview"
rate_limit:
retry_after: 60
google-gemini-pro:
api_key: "${GOOGLE_API_KEY}"
models:
- "gemini-pro"
rate_limit:
retry_after: 60
đ§Ș Verifizierung
Test 1: Modellbezogene Isolierung nach dem Fix bestÀtigen
# Step 1: Trigger rate limit on model A
curl -X POST https://api.openclaw.io/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "gemini-3.1-pro-preview-customtools", "messages": [{"role": "user", "content": "test"}]}'
# Expected: 429 from Google API
# Verify with: echo $? (should be non-zero)
# Step 2: Immediately test model B access
curl -X POST https://api.openclaw.io/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "gemini-3.0-pro-preview", "messages": [{"role": "user", "content": "test"}]}'
# Expected: 200 OK or valid API response (not gateway backoff error)
Test 2: Modellspezifischen Backoff-Zustand verifizieren
PrĂŒfen Sie den internen Zustand des Gateways (falls ĂŒber Admin-Endpunkt verfĂŒgbar):
GET /admin/rate-limit-status
# Expected response structure:
{
"providers": {
"google": {
"cooldown": false,
"models": {
"gemini-3.1-pro-preview-customtools": {
"cooldown": true,
"retry_after": 120,
"expires_at": "2024-01-15T10:30:00Z"
},
"gemini-3.0-pro-preview": {
"cooldown": false
}
}
}
}
}
Test 3: Gleichzeitiger ModellverfĂŒgbarkeitstest
# Run concurrent requests to different models
for model in "gemini-3.1-pro-preview-customtools" "gemini-3.0-pro-preview" "gemini-pro"; do
echo "Testing: $model"
curl -s -o /dev/null -w "%{http_code}\n" \
-X POST https://api.openclaw.io/v1/chat/completions \
-H "Content-Type: application/json" \
-d "{\"model\": \"$model\", \"messages\": [{\"role\": \"user\", \"content\": \"test\"}]}"
done
# Expected:
# gemini-3.1-pro-preview-customtools: 429 (rate limited)
# gemini-3.0-pro-preview: 200 (independent quota)
# gemini-pro: 200 (independent quota)
Test 4: Backoff-Ablauf-Verifizierung
# Wait for cooldown to expire
echo "Waiting for model cooldown expiration..."
sleep 130 # retry_after + buffer
# Verify previously rate-limited model is accessible
curl -X POST https://api.openclaw.io/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "gemini-3.1-pro-preview-customtools", "messages": [{"role": "user", "content": "test"}]}'
# Expected: 200 OK
Erfolgskriterien
- â
Nach Ratenlimit auf
gemini-3.1-pro-preview-customtoolsbleiben anderegoogle-Modelle erreichbar. - â Der modellspezifische Backoff-Zustand wird korrekt verfolgt und lĂ€uft unabhĂ€ngig ab.
- â Das Gateway lehnt Anfragen an nicht ratenlimitierte Modelle nicht vorab ab.
- â Fallback-Ketten funktionieren korrekt, wenn das primĂ€re Modell nicht verfĂŒgbar ist.
â ïž HĂ€ufige Fehler
Umgebungsspezifische Fallen
Docker-Container-Caching
# Pitfall: Container filesystem may cache rate limit state
# Restarting containers may not reset state if persistence is enabled
docker-compose down
docker volume prune openclaw-cache # Clear cached state
docker-compose up -d
Kubernetes-Volume-Mounts
Falls persistente Volumes fĂŒr Ratenlimit-Verfolgung verwendet werden:
# Verify PVC is not stale after config changes
kubectl get pvc | grep openclaw
kubectl describe pvc openclaw-cache
# May need to delete and recreate if schema changed
kubectl delete pvc openclaw-cache
# Then restart deployments
macOS-Entwicklungsumgebung
# Pitfall: Local rate limit state may persist across terminal sessions
# Clear any local state files
rm -rf ~/.openclaw/cache/*
rm -rf .openclaw/state.json
Konfigurationsfehler
Falscher Anbietername in der Fallback-Kette
# WRONG: Typos in provider name cause silent failures
models:
- name: "gemini-3.0-pro-preview"
provider: "googel" # Typo - will not match actual provider
# CORRECT:
models:
- name: "gemini-3.0-pro-preview"
provider: "google"
Ăberlappende Modelldeklarationen
# WRONG: Same model declared multiple times
models:
- name: "gemini-3.0-pro-preview"
provider: "google"
- name: "gemini-3.0-pro-preview" # Duplicate
provider: "google"
fallback_models: [...]
API-SchlĂŒssel-Umfang-Mismatch
# Pitfall: Google API keys may have different quotas per project
# If using separate provider instances, ensure they use keys with adequate quotas
# Verify in Google Cloud Console:
# APIs & Services > Enabled APIs > Vertex AI API > Quotas
Testen von GrenzfÀllen
Ratenlimit auf dem letzten verfĂŒgbaren Modell
# Scenario: All models under a provider are rate-limited
# Expected: Should return clear error, not silent success
# Verify error response includes all affected models
curl -X POST https://api.openclaw.io/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "gemini-3.0-pro-preview", "messages": [{"role": "user", "content": "test"}]}'
# Check response contains actionable information
# Should NOT be empty 200 OK
Schneller Modellwechsel
# Pitfall: Race condition during rapid switching may bypass backoff
# Test with concurrent requests
ab -n 100 -c 10 -T 'application/json' \
-p request.json \
https://api.openclaw.io/v1/chat/completions
# Verify all requests are properly rate-limited or processed
đ Zugehörige Fehler
| Fehlercode | Beschreibung | Verbindung |
|---|---|---|
429 RESOURCE_EXHAUSTED | Google API gab Ratenlimit-Fehler zurĂŒck | Quellfehler, der Anbieter-Backoff auslöst |
503 Service Unavailable | Anbieter vorĂŒbergehend nicht verfĂŒgbar | Nachgelagert bei verlĂ€ngertem Anbieter-Backoff |
500 Internal Server Error | Gateway-Fehler wÀhrend Backoff-Handling | Unbehandelte Ausnahme in der Ratenlimit-Middleware |
ENOTFOUND | DNS-Auflösung fehlgeschlagen fĂŒr Google API | UnabhĂ€ngig, kann aber als Ratenlimit fehldiagnostiziert werden |
ETIMEDOUT | Verbindungs-Timeout zu Google API | UnabhÀngig, kann aber falsche Backoff-Logik auslösen |
INVALID_ARGUMENT | Fehlerhafte Anfrage an Gemini API | Kann in der Fehlerbehandlung als Ratenlimit fehlgeleitet werden |
Historischer Kontext
Dieses Problem bezieht sich auf breitere Muster im Design von Multi-Tenant-API-Gateways:
- ĂbermĂ€Ăig breite Circuit Breaker: Circuit-Breaker-Muster werden auf Anbieterebene angewendet, obwohl sie auf Modell-/Bereitstellungsebene arbeiten sollten.
- Kollision gemeinsam genutzter ZustÀnde: Mehrere unabhÀngige Ressourcen teilen sich einen einzigen Ratenlimit-ZÀhler.
- Unzureichender Fehlerkontext: 429-Antworten von Google enthalten
retryInfo, das angibt, welches Kontingent erschöpft ist, aber dies wird möglicherweise nicht geparst.
Zugehörige GitHub-Issues
- Rate limiting should be scoped per-model not per-provider - Feature-Anfrage fĂŒr Modell-Ebene-Isolierung
- Google Gemini provider backoff blocks all models - Doppeltes Tracking-Issue
- Add retry-after parsing from Google 429 responses - Erweiterung fĂŒr genaue Cooldown-Berechnung