Einladen & verdienen

So funktionieren Einladungsboni

Teile deinen Einladungslink. Registriert sich ein Freund darüber und lädt Guthaben auf, erhältst du die angezeigte Prämie für seine weiteren Aufladungen.

OpenRouter-Ratelimits und HTTP 429: Fehlerdiagnose und Wiederherstellung

Ein praxisnaher Leitfaden zur Diagnose von HTTP-429- und HTTP-402-Fehlern bei OpenRouter: Unterschiede zwischen Free-Tier-Kontingenten, Plattform- und Upstream-Limits, Header-Analyse und ein robustes Python-Retry-Skript.

Inhalt
OpenRouter-Ratelimits und HTTP 429: Fehlerdiagnose und Wiederherstellung

Beim Senden hoher Anfragevolumina an KI-Modelle über das OpenRouter-Gateway stoßen Client-Anwendungen regelmäßig auf den Statuscode HTTP 429 Too Many Requests. Da OpenRouter Dutzende unabhängiger Inferenz-Provider bündelt, kann dieser Fehler auf völlig unterschiedlichen Ebenen der Infrastruktur auftreten. Ein naiver, unmittelbarer Wiederholungsversuch führt häufig zu Client-Sperren oder verschwendeten Retry-Versuchen. Um einen stabilen Anfragenfluss wiederherzustellen, muss die genaue Fehlerebene identifiziert und die passende Gegenmaßnahme gewählt werden: Abwarten mit Backoff, Reduzieren der Parallelität, Wechseln des Modell-Providers oder Anpassen des Ausgabenlimits.

Ebenen der Beschränkungen: Free-Tier, Plattform und Upstream

Die offizielle Dokumentation zu OpenRouter Limits unterscheidet zwischen plattformweiten Ratelimits des Dienstes, dem Durchsatz einzelner Provider und Sperren aufgrund des Kontostands.

Auf der Seite OpenRouter Pricing gilt für den kostenlosen Tarif eine Obergrenze von 50 Anfragen pro Tag für öffentlich zugängliche freie Modelle (gekennzeichnet durch das Suffix :free). Da sich exakte Grenzwerte für Anfragen pro Minute (RPM) und Stufen-Schwellenwerte im Laufe der Zeit ändern können, sollten aktuelle numerische Werte stets in der aktuellen Limits-Tabelle überprüft werden.

Bei der Fehleranalyse ist es entscheidend, die Ebenen hinter dem Statuscode HTTP 429 und dem verwandten Status HTTP 402 sauber zu trennen:

  1. Ratelimits der OpenRouter-Plattform. Diese treten auf, wenn der Router selbst zu schnell mit Anfragen überflutet wird. Das tägliche Kontingent des kostenlosen Pools gehört ebenfalls zu dieser Kategorie plattformseitiger Limits (und nicht zu einer separaten Drittanbieter-Beschränkung): Wird das Limit von 50 Anfragen pro Tag für freie Modelle überschritten, lehnt die Plattform eingehende Anfragen bis zum Zurücksetzen des Tageszählers ab. Bei Erreichen eines Plattform-Ratelimits liefert der Server die HTTP-Header X-RateLimit-Limit, X-RateLimit-Remaining und X-RateLimit-Reset zurück. Erfolgreiche Antworten (HTTP 200) enthalten diese Betriebs-Header nicht, sodass Client-Anwendungen im fehlerfreien Normalbetrieb nicht auf sie zurückgreifen können, um Limits vorherzusagen.
  2. Ratelimits des Upstream-Providers. Modelle werden physisch auf der Infrastruktur bestimmter Partnerunternehmen gehostet und ausgeführt (wie etwa Anthropic, Meta, DeepSeek, Mistral oder spezialisierten Cloud-Hostern). Ist die Infrastruktur dieses Partners überlastet, leitet OpenRouter den Statuscode 429 an den Client weiter. In der Antwortstruktur enthält das Feld error.metadata.provider_code den ursprünglichen Fehlercode des Upstream-Providers, sofern verfügbar (beispielsweise 429), und nicht den Namen oder String-Bezeichner des Anbieters.
  3. Finanzielle Beschränkungen (HTTP 402 Payment Required). Die Dokumentation zu OpenRouter Limits trennt Abrechnungsgrenzen ausdrücklich von frequenzbasierten Ratelimits. Ein 402-Status signalisiert ein unzureichendes oder negatives Organisationsguthaben oder das Erreichen des Ausgabenlimits eines einzelnen API-Schlüssels (Key-Cap) – und nicht ausschließlich einen exakt bei null liegenden Saldo.

Aktuelle Schlüsselparameter lassen sich über einen direkten API-Aufruf einsehen:

curl -s -X GET https://openrouter.ai/api/v1/key \
  -H "Authorization: Bearer $OPENROUTER_API_KEY"

Die Antwort liefert die Felder usage, limit_reset und limit_remaining. Der Wert limit_remaining: null zeigt an, dass für diesen konkreten API-Schlüssel keine lokale Ausgabenobergrenze (Key-Cap) festgelegt wurde. Dieser Wert bestätigt jedoch nicht, ob auf dem Hauptkonto der Organisation ein Guthaben vorhanden ist; er hebt lediglich künstliche Limits für diesen spezifischen Token auf.

Diagnose-Übersichtstabelle

Antwortcode & SignaleDiagnosequelleUrsacheClient-Aktion
HTTP 402 Payment RequiredEndpunkt GET /api/v1/key oder DashboardUnzureichendes/negatives Organisationsguthaben oder Ausgabenlimit des Schlüssels erreicht (limit_remaining: 0)Guthaben aufladen oder Schlüssel-Limit erhöhen; programmgesteuerte Retries ohne Änderungen sind zwecklos
HTTP 429 mit X-RateLimit-*-HeadernGateway-HTTP-Antwort-HeaderGleichzeitigkeits- oder Frequenzlimits der OpenRouter-Plattform überschrittenRetry-After-Header auswerten und Anzahl paralleler Threads reduzieren
HTTP 429 mit Code in provider_codeJSON-Feld error.metadata.provider_code (optional)Überlastung oder Ausfall des Upstream-Providers (ursprünglicher Fehlercode des Upstreams)Modell- oder Providerwechsel kann helfen, garantiert aber keine Wiederherstellung; spezifischen Provider unter Activity > provider_responses identifizieren
HTTP 429 bei :free-ModellenAbschnitt OpenRouter PricingTägliches Plattformlimit (50 Anfragen/Tag) oder verfügbare Kapazität erschöpftAuf kostenpflichtiges Modell upgraden oder Ausführung verschieben
HTTP 429 bei komplexem RoutingDashboard: Activity > Anfrage > View Raw MetadataAusfall von Zwischenknoten im Objekt provider_responsesAusfallenden Provider zuordnen und Fallback-Kette im BYOK/Routing-Leitfaden überprüfen

Analyse zweier Szenarien: Key-Cap vs. Provider-Ausfall

Wie eine Client-Anwendung bei fehlschlagenden Anfragen reagieren sollte, hängt von der Auswertung der Metadaten ab. Nachfolgend werden zwei hypothetische Szenarien dargestellt (illustrative Beispiele, keine Beobachtungen eines realen Kontos).

Szenario 1 (hypothetisch): Erschöpfung des lokalen Token-Limits

In diesem hypothetischen Szenario erhält ein Hintergrund-Worker eine Ablehnung mit dem Status HTTP 402. Ein positives Organisationsguthaben ist hier eine explizite Grundannahme, die separat über das Web-Dashboard überprüft wurde (die Antwort des Key-Endpunkts selbst bestätigt das Gesamtkontoguthaben nicht). Die Abfrage des Endpunkts https://openrouter.ai/api/v1/key liefert:

{
  "data": {
    "label": "worker-key",
    "usage": 25.04,
    "limit": 25.0,
    "is_free_tier": false,
    "limit_remaining": 0.0,
    "limit_reset": null
  }
}

Obwohl das primäre Guthaben voraussetzungsgemäß positiv ist, liegt das Feld limit_remaining bei null. Der Token hat das vom Administrator konfigurierte Ausgabenlimit von 25 Dollar erreicht. Sämtliche automatisierten Wiederholungsversuche mit diesem Schlüssel werden wiederholt mit demselben 402-Fehler fehlschlagen. Der Worker-Prozess muss sofort beendet werden und einen Administrator benachrichtigen, um das Ausgabenlimit anzupassen.

Szenario 2 (hypothetisch): Überlastung des Upstream-Providers

Betrachten wir als anschauliches Beispiel einen Fall, in dem eine eingehende Anfrage aufgrund eines Upstream-Ausfalls den Status HTTP 429 zurückgibt. Der bloße Erhalt des Status 429 erlaubt keine Rückschlüsse auf den Gesamtzustand des Gateways oder das verbleibende Kontoguthaben. Die Fehlerantwort kann einen optionalen Metadatenblock enthalten:

{
  "error": {
    "message": "Provider returned rate limit error",
    "code": 429,
    "metadata": {
      "provider_code": 429
    }
  }
}

Das Feld error.metadata.provider_code ist optional und enthält den Rohstatuscode des Upstream-Providers, wenn dieser vorliegt (in diesem Beispiel 429) – nicht jedoch den Namen oder Bezeichner des Providers. Das Vorhandensein dieses Codes allein verrät noch nicht, welcher konkrete Host die Anfrage abgewiesen hat.

Um den ausfallenden Provider zu ermitteln, navigiert man in der Verwaltungskonsole zu: Activity > konkrete Anfrage > View Raw Metadata. Das Objekt provider_responses listet alle evaluierten Provider samt ihrer Rückgabewerte auf, wie im Routing-Leitfaden beschrieben. Der Wechsel zu einem anderen Provider oder einem anderen Zielmodell kann in einer solchen Situation helfen, garantiert jedoch keine sofortige Wiederherstellung.

Python-3-Client-Skript für Wiederholungsversuche

Wenn ein HTTP-429-Status vorübergehender Natur ist, wird die Verzögerung vor dem nächsten Versuch über den Retry-After-Header berechnet. Der Server übermittelt diesen Header entweder als ganzzahlige Anzahl von Sekunden oder als Datumszeichenkette im HTTP-Format.

Die folgende Implementierung nutzt ausschließlich die Standardbibliothek von Python 3. Sie behandelt gezielt nur HTTP-429-Fehler, wendet bei fehlendem Header ein exponentielles Backoff mit Zufallsvarianz (Jitter) an und bricht die Ausführung ab, wenn der Server eine Wartezeit von mehr als 60 Sekunden anfordert.

import email.utils
import json
import os
import random
import sys
import time
import urllib.error
import urllib.request

API_KEY = os.environ.get("OPENROUTER_API_KEY")
MODEL_ID = os.environ.get("OPENROUTER_MODEL_ID", "openai/gpt-4o-mini")
MAX_ATTEMPTS = 3
MAX_ACCEPTABLE_WAIT = 60.0


def parse_retry_after(header_value: str | None) -> float | None:
    if not header_value:
        return None
    raw = header_value.strip()
    if raw.isdigit():
        return max(0.0, float(raw))
    try:
        parsed_date = email.utils.parsedate_to_datetime(raw)
        delay = parsed_date.timestamp() - time.time()
        return max(0.0, delay)
    except Exception:
        return None


def execute_completion(prompt_text: str) -> str | None:
    if not API_KEY:
        sys.stderr.write("Переменная окружения OPENROUTER_API_KEY не задана.\n")
        return None

    endpoint = "https://openrouter.ai/api/v1/chat/completions"
    payload = json.dumps(
        {
            "model": MODEL_ID,
            "messages": [{"role": "user", "content": prompt_text}],
        }
    ).encode("utf-8")

    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    }

    for attempt in range(1, MAX_ATTEMPTS + 1):
        req = urllib.request.Request(endpoint, data=payload, headers=headers, method="POST")
        try:
            with urllib.request.urlopen(req, timeout=30) as response:
                status_code = response.getcode()
                body = response.read().decode("utf-8")
                if status_code == 200:
                    data = json.loads(body)
                    return data["choices"][0]["message"]["content"]
        except urllib.error.HTTPError as err:
            if err.code == 429:
                retry_header = err.headers.get("Retry-After")
                server_delay = parse_retry_after(retry_header)

                if server_delay is not None:
                    wait_seconds = server_delay
                else:
                    base_delay = 2.0 ** attempt
                    wait_seconds = base_delay + random.uniform(0.1, 1.0)

                if wait_seconds > MAX_ACCEPTABLE_WAIT:
                    sys.stderr.write(
                        f"Сервер запросил паузу {wait_seconds:.1f} с. "
                        "Ожидание превышает 60 секунд. Запрос отменен.\n"
                    )
                    return None

                if attempt == MAX_ATTEMPTS:
                    sys.stderr.write("Исчерпан лимит из 3 попыток на статус 429.\n")
                    return None

                sys.stderr.write(
                    f"Получен 429. Попытка {attempt} завершилась неудачей. "
                    f"Пауза {wait_seconds:.2f} с перед следующим запросом.\n"
                )
                time.sleep(wait_seconds)
                continue
            elif err.code == 402:
                sys.stderr.write("Ошибка 402: проверьте баланс счета и лимит ключа.\n")
                return None
            else:
                sys.stderr.write(f"HTTP-ошибка {err.code}: запрос отклонен без повтора.\n")
                return None
        except urllib.error.URLError as err:
            sys.stderr.write(f"Сетевой сбой: {err.reason}. Повтор отменен.\n")
            return None

    return None


if __name__ == "__main__":
    result = execute_completion("Назови три базовых принципа надежности сетевых API.")
    if result:
        print(result)

Da der obige Skriptausschnitt die ursprünglichen russischen Diagnose-Meldungen exakt beibehält, erläutert die folgende Übersicht den internen Entscheidungsbaum und die entsprechenden Bedeutungen auf Deutsch:

  • Переменная окружения OPENROUTER_API_KEY не задана. („Umgebungsvariable OPENROUTER_API_KEY ist nicht gesetzt“): Zeigt an, dass die erforderliche Umgebungsvariable fehlt; die Funktion bricht sofort ab, ohne Netzwerkanfragen zu initiieren.
  • Сервер запросил паузу ... Ожидание превышает 60 секунд. Запрос отменен. („Server forderte Pause von … s an. Wartezeit überschreitet 60 Sekunden. Anfrage abgebrochen.“): Wird ausgelöst, wenn der Header Retry-After eine Wartezeit über MAX_ACCEPTABLE_WAIT (60 Sekunden) vorschreibt; die Ausführung bricht ab, um Worker-Prozesse nicht dauerhaft zu blockieren.
  • Исчерпан лимит из 3 попыток на статус 429. („Limit von 3 Versuchen für Status 429 erschöpft.“): Alle drei Wiederholungsversuche bei HTTP 429 wurden erfolglos aufgebraucht.
  • Получен 429. Попытка ... завершилась неудачей. Пауза ... с перед следующим запросом. („429 empfangen. Versuch X fehlgeschlagen. Pause von Y s vor nächster Anfrage.“): Protokolliert einen zwischenzeitlichen 429-Fehler bei Versuch X und pausiert für die berechnete Backoff-Dauer Y vor dem nächsten Versuch.
  • Ошибка 402: проверьте баланс счета и лимит ключа. („Fehler 402: Kontoguthaben und Schlüssellimit prüfen.“): Nicht behebbarer HTTP-402-Zahlungsfehler, der anzeigt, dass das Kontoguthaben aufgebraucht ist oder das Ausgabenlimit des Schlüssels erreicht wurde; es erfolgen keine weiteren Versuche.
  • HTTP-ошибка ...: запрос отклонен без повтора. („HTTP-Fehler {code}: Anfrage abgelehnt ohne Wiederholung.“): Protokolliert jeden anderen HTTP-Fehlercode und bricht die Ausführung ohne Retry ab.
  • Сетевой сбой: ... Повтор отменен. („Netzwerkfehler: {reason}. Wiederholung abgebrochen.“): Fängt allgemeine Socket- oder Netzwerkfehler (URLError) ab und bricht ab, um erneute Aufrufe bei unklarem Übertragungsstatus zu vermeiden.
  • Der Test-Prompt Назови три базовых принципа надежности сетевых API. bedeutet übersetzt: „Nenne drei grundlegende Prinzipien für die Zuverlässigkeit von Netzwerk-APIs.“

Wiederholen von Netzwerkanfragen und Nebeneffekte

Beim Entwurf von Tool-Calling-Abläufen innerhalb autonomer Agenten-Schleifen erfordert das Wiederholen von HTTP-Anfragen größte Sorgfalt. Hat das Modell in einem vorherigen Schritt bereits ein externes Tool aufgerufen, das den Zustand eines externen Systems verändert hat (z. B. ein Datenbankeintrag, das Auslösen einer Zahlung oder das Erstellen eines Tickets), führt das blinde Wiederholen der gesamten Kette zu doppelten Ausführungen. Anfragen dürfen keinesfalls automatisch wiederholt werden, wenn verknüpfte Business-Tools bereits ausgeführt wurden oder das Netzwerk ein unklares Ergebnis geliefert hat (wie ein Verbindungsabbruch oder Socket-Timeout, bei dem ungewiss ist, ob der Server den Prompt bereits verarbeitet hat).

Im obigen Skript beschränken sich Wiederholungen streng auf Anfragen, die explizit mit dem Statuscode HTTP 429 abgewiesen wurden. Dabei darf Textgenerierung niemals als strikt idempotent oder kostenlos vorausgesetzt werden: Wiederholte Aufrufe belasten Kontingente und Budgets, und das stochastische Verhalten von Sprachmodellen kann zu abweichenden Ergebnissen führen. Tritt ein Fehler während der Ausführung eines externen Befehls durch einen Agenten auf, sollte der Systemzustand vor Wiederaufnahme des Modell-Dialogs über ein Aktionsprotokoll synchronisiert werden.

Aufbau ausfallsicherer Routing-Architekturen

Auf der Preisseite schreibt der Free-Tarif ein plattformseitiges Limit von 50 Anfragen pro Tag für freie Modelle vor. Das in der Dokumentation hervorgehobene Fehlen von Plattform-Ratelimits bezieht sich auf den Wechsel zu einem kostenpflichtigen Modell und nicht auf das bloße Aufladen von Guthaben – eine Einzahlung auf das Konto hebt Limits für :free-Endpunkte nicht automatisch auf. Die exakten Bedingungen und Kontingente für das eigene Konto sollten stets in der aktuellen Limits-Tabelle geprüft werden. Zudem schließt auch die Nutzung kostenpflichtiger Modelle eine temporäre Überlastung einzelner Servercluster der Upstream-Provider nicht aus (wenngleich ein Providerwechsel helfen kann, garantiert er keine sofortige Verfügbarkeit).

Für einen zuverlässigen Produktionsbetrieb kombinieren Entwicklungsteams in der Praxis mehrere Schutzmaßnahmen:

  • Definieren von Fallback-Modellen im models-Array von OpenRouter, sodass der Router Anfragen bei Ausfall der primären Wahl automatisch an eine Ersatzinstanz übergibt.
  • Begrenzen der maximalen Anzahl paralleler Anfragen auf Client-Seite über Task-Queues, Semaphore oder Token-Bucket-Verfahren.
  • Bereitstellen einer unabhängigen Ausweichroute über alternative Multi-Modell-APIs mit kompatiblem Anfrageformat für geschäftskritische Infrastruktur, um Traffic bei längeren Gateway-Ausfällen nahtlos migrieren zu können.

Bereit, Ihren LLM-Workflow zu optimieren?

Verbinden Sie Modelle über eine API, verwalten Sie Schlüssel und behalten Sie KI-Kosten im Blick.

Kostenlos starten