DE ▾
API-Schlüssel erhalten

Unzensierte API-Fehlercodes & Fehlerbehebung

Fehler sind nicht schlimm, schlimm ist nur Unsicherheit beim Retry. Dieses Handbuch zerlegt Statuscodes: Auslöser, Diagnose, Lösung. Fehler-Body ist immer JSON mit code und message. Lies zuerst den Body, nicht nur den Statuscode. Inklusive Retry-Code mit Backoff, Client-Rate-Limiting und Checkliste.

Aktualisiert am

Kernpunkte

  • Nur 429 und 503 sind für automatisches Retry geeignet. Bei allen anderen Statuscodes verschwendet Retry nur Anfragen.
  • 402 no_credit bedeutet kein Guthaben oder abgelaufenes Testguthaben. 403 content_blocked bedeutet Inhalt blockiert. Beides sind keine Netzwerkfehler.
  • Retry mit exponentiellem Backoff und Jitter sowie Maximalanzahl.
  • 300 Anfragen/Minute pro Key. Batch-Aufgaben müssen clientseitig gedrosselt werden.

Fehler-Body-Format & Lesereihenfolge

Alle Fehlerantworten haben dieselbe Struktur:

{"error":{"code":"...","message":"..."}}

Feste Lesereihenfolge in drei Schritten:

  1. HTTP-Statuscode für die Kategorie;
  2. error.code für die genaue Ursache (Branching im Code);
  3. error.message für Menschen (Logs), nicht für String-Matching.

Unterscheide klar: Lösungen durch Wiederholung (429, 503, Timeout) und Lösungen durch Änderung (Rest). Vermischung ist ein häufiger Fehler, z. B. bei 402.

Logge immer vier Felder: Zeitstempel, Statuscode, error.code und geschätzte prompt_tokens. So siehst du sofort, ob eine Fehlerklasse zunimmt. Lege eine Regel fest: 402 löst sofort aus (Service nicht verfügbar); 429 nur bei hoher Rate, da gelegentliche 429 keine Behandlung benötigen.

Statuscode-Schnellreferenz

Statuscodeerror.codeBedeutungRetry?
400—Ungültige Anfrage, z. B. wenn prompt plus max_tokens 100k übersteigenNein
401—Ungültiger oder fehlender KeyNein
402no_creditGuthaben aufgebraucht oder Testguthaben abgelaufenNein
403content_blockedInhalt blockiertNein
404—Endpunkt nicht gefundenNein
429—Rate-Limit erreichtJa, Backoff
503upstream_busyDienst vorübergehend ausgelastetJa, nach einigen Sekunden

„—“ bedeutet: Kein fester Code-String. Branching nach Statuscode reicht.

4xx: Anfrage ändern, nicht erneut versuchen

400 Ungültige Anfrage

  • Ursache 1: JSON-Fehler (fehlende Escaping-Zeichen).
  • Ursache 2: prompt + max_tokens > 100.000. Häufig bei langen Dialogen.
  • Ursache 3: Request-Body > 8 MB.
  • Lösung: JSON-Serialisierung; Token vorab schätzen; bei Limit History kürzen oder max_tokens senken. Siehe Langer Kontext in der Praxis.

401 Schlüssel-Probleme

  • Header fehlt oder Bearer -Präfix fehlt.
  • Key neu generiert, alter Key sofort ungültig, aber noch im Einsatz.
  • Umgebungsvariablen nicht in Container oder Cron-Jobs übernommen.

402 no_credit

Das Guthaben ist aufgebraucht oder die 7-Tage-Testphase ist abgelaufen. Gehe zurKontoseite, um dein Prepaid-Guthaben aufzuladen, um fortzufahren. Wir empfehlen, dein Service-Balance selbst zu überwachen, statt erst auf Benutzerfehler zu warten.

403 content_blocked

Inhalt blockiert. Legitime erwachsene Inhalte, fiktionale und kontroverse Themen werden nicht abgelehnt, aber sexuell explizite Inhalte mit Minderjährigen werden immer blockiert, einschließlich Romanen und Rollenspielen. Bei einem 403 solltest du Eingabe und Verlauf auf solche Inhalte prüfen, statt die Formulierung zu ändern und es erneut zu versuchen.

404 Endpunkt nicht gefunden

Es gibt nur zwei Endpunkte: POST /v1/chat/completions und GET /v1/models. Ein fehlender /v1-Pfad, ein zusätzlicher Slash, Tippfehler oder das Anfordern nicht unterstützter Endpunkte wie Embeddings oder Bilder führen zu einem 404.

Eine leicht zu missverstehende Kategorie in 400: Die Token-Anzahl bei langen Dialogen wächst linear mit den Runden. Tests tagsüber sind OK, doch nach Dutzenden Runden tritt plötzlich 400 auf. Das ist keine Instabilität, sondern das Kontextfenster ist voll. Begrenze die Historie oder komprimiere alte Inhalte. Schätze den Verbrauch vor der Anfrage ab.

Ein Trick zur Fehlersuche bei 401: Gib die ersten und letzten vier Zeichen des API-Schlüssels in die Logs aus, nicht den vollständigen Schlüssel, und vergleiche ihn mit dem auf der Kontoseite angezeigten. So stellst du sicher, dass der im Prozess gelesene Schlüssel auch wirklich der ist, den du meinst. In Container- und Cron-Job-Umgebungen sind fehlende Umgebungsvariablen oder das Lesen veralteter Werte die häufigste Ursache.

429 und 503: Zwei Fehlerklassen, die einen Retry erlauben

429 Ratenlimit

Pro API-Schlüssel sind 300 Anfragen pro Minute erlaubt. Batch-Aufgaben, mehrere Instanzen, die denselben Schlüssel teilen, oder Retry-Stürme lösen dies aus. Die Korrektur erfolgt in zwei Schichten: Client-seitiges Rate-Limiting (siehe Code weiter unten) und exponentieller Backoff bei 429.

503 upstream_busy

Der Dienst ist vorübergehend ausgelastet. Warte ein paar Sekunden und versuche es erneut. Sende nicht sofort mehrere Anfragen hintereinander und versuche auch nicht, innerhalb einer Sekunde zehn Mal zu wiederholen, das verschlimmert die Situation nur.

Netzwerk-Timeout

Die Generierung langer Texte dauert länger, setze das Timeout nicht zu niedrig an, z. B. 120 Sekunden. Achte beim Retry nach einem Timeout darauf: Die vorherige Anfrage könnte bereits auf dem Server ausgeführt worden sein, sodass ein erneuter Aufruf die Credits doppelt verbraucht. Bei Generierungsanfragen also die Retry-Anzahl gering halten und idealerweise Streaming nutzen, um die Wartezeit pro Anfrage zu verkürzen.

import os
import random
import time
import requests

URL = "https://api.wushenchaapi.com/v1/chat/completions"
HEADERS = {
    "Authorization": "Bearer " + os.environ["API_KEY"],
    "Content-Type": "application/json",
}
RETRYABLE = {429, 503}          # 只重试这两类
FATAL = {400, 401, 402, 403, 404}

class ApiError(Exception):
    def __init__(self, status, code, message):
        super().__init__(f"{status} {code}: {message}")
        self.status, self.code = status, code

def call(payload, max_retries=5, base=1.0, cap=30.0):
    for attempt in range(max_retries + 1):
        try:
            r = requests.post(URL, headers=HEADERS, json=payload, timeout=120)
        except (requests.ConnectionError, requests.Timeout):
            r = None                      # 网络层失败,按可重试处理
        if r is not None and r.ok:
            return r.json()
        if r is not None:
            try:
                err = r.json().get("error", {})
            except ValueError:
                err = {}
            if r.status_code in FATAL or r.status_code not in RETRYABLE:
                raise ApiError(r.status_code, err.get("code"), err.get("message"))
        if attempt == max_retries:
            raise ApiError(r.status_code if r is not None else 0, "retry_exhausted", "重试次数用尽")
        delay = min(cap, base * (2 ** attempt)) * random.uniform(0.5, 1.0)
        time.sleep(delay)

if __name__ == "__main__":
    out = call({"model": "uncensored", "max_tokens": 100,
                "messages": [{"role": "user", "content": "回复一个字:好"}]})
    print(out["choices"][0]["message"]["content"])

Wichtig: Die Backoff-Formel lautet min(cap, base × 2^n) × Zufallsfaktor. Der Zufalls-Jitter verhindert, dass mehrere Clients gleichzeitig mit Retries kollidieren. Statuscodes in der FATAL-Liste werden niemals wiederholt.

Client-Rate-Limiting und Diagnose-Anfragen

Statt erst auf 429 zu warten und dann zu drosseln, solltest du im Voraus limitieren. Das folgende Tool stellt sicher, dass die Anzahl der Anfragen pro Minute unter dem eingestellten Wert bleibt, und ist threadsicher:

import threading
import time

class RateGate:
    """简单的客户端限速:保证一分钟内请求数不超过 limit。"""
    def __init__(self, limit=240):          # 留出余量,低于 300/分钟
        self.limit, self.stamps, self.lock = limit, [], threading.Lock()

    def wait(self):
        while True:
            with self.lock:
                now = time.time()
                self.stamps = [t for t in self.stamps if now - t < 60]
                if len(self.stamps) < self.limit:
                    self.stamps.append(now)
                    return
                sleep_for = 60 - (now - self.stamps[0])
            time.sleep(max(sleep_for, 0.05))

Die sauberste Methode zur Fehlersuche ist, den Anwendungscode zu verlassen und eine minimale Anfrage mit curl zu senden. Die Option -i zeigt gleichzeitig die Statuszeile und die Antwort-Header:

curl -i https://api.wushenchaapi.com/v1/chat/completions \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"uncensored","max_tokens":20,"messages":[{"role":"user","content":"ping"}]}'

Wenn curl funktioniert, deine Anwendung aber nicht, liegt das Problem an deinem Code oder deiner Umgebung (Proxy, Umgebungsvariablen, Kodierung). Wenn auch curl fehlschlägt, prüfe den API-Schlüssel, das Guthaben und das Netzwerk.

Warum das Limit bei 240 und nicht bei 300 liegt: Bei Multi-Instance-Deployments drosseln jede Instanz separat, sodass die Summe dennoch das Gesamtlimit überschreiten kann. Hinzu kommt, dass Retries zusätzliches Kontingent verbrauchen. Eine Reserve von 20 % ist daher die sicherere Wahl. Wenn du mehrere Instanzen hast, teile das Gesamtkontingent gleichmäßig auf jede Instanz auf oder nutze einen gemeinsamen Zähler für das zentrale Scheduling.

Fehlersuche-Checkliste

  1. Lese den error.code im Body, schau nicht nur auf den Statuscode.
  2. 401: Schlüsselpräfix, Umgebungsvariablen, ob der Schlüssel neu generiert wurde.
  3. 400: Ist das JSON gültig? Übersteigen prompt + max_tokens 100.000? Ist der Request-Body größer als 8 MB?
  4. 402: Guthaben und Gültigkeitsdauer des Testguthabens.
  5. 403: Enthalten Eingabe und Verlauf verbotene Inhalte?
  6. 404: Ist der Pfad /v1/chat/completions oder /v1/models?
  7. 429: Teilen mehrere Instanzen denselben API-Schlüssel? Wurde Client-Rate-Limiting implementiert?
  8. 503: Wurde Backoff-Retry implementiert? Ist der Abstand mindestens einige Sekunden?
  9. Timeout: Reicht das Timeout? Kann auf Streaming umgestellt werden?
  10. Wenn alles ausgeschlossen ist: Reproduziere das Problem mit einer minimalen curl-Anfrage.

Fang mit demAnleitungan. Mehr Parameter findest du in derDokumentation.

Anwendung der Checkliste: Gehe bei Problemen die Liste von oben nach unten durch, statt wild zu springen. Die meisten „seltsamen“ Fehler liegen in den ersten vier Punkten.

Ein zusätzlicher Tipp: Schreibe die Ergebnisse jeder Fehlersuche in die Teamdokumentation zurück. Bei ähnlichen Fehlern weißt du beim nächsten Mal sofort, wo du ansetzen musst.

Häufig gestellte Fragen

Wie lange muss ich auf einen 503 warten, bevor ich es erneut versuche?

Ein paar Sekunden reichen. Warte beim ersten Mal ein bis zwei Sekunden, erhöhe dann exponentiell und füge einen Zufalls-Jitter hinzu. Setze eine maximale Retry-Anzahl.

Warum erhalte ich bei meinen Anfragen ständig einen 402?

Guthaben aufgebraucht oder 7-Tage-Testguthaben abgelaufen. Nach dem Aufladen des Prepaid-Guthabens ist es wieder verfügbar; das Guthaben verfällt nicht.

Kann 403 content_blocked durch Umformulierung umgangen werden?

Versuche es nicht. Sexuelle Inhalte mit Minderjährigen werden unter allen Umständen blockiert, einschließlich Romanen und Rollenspielen. Normale erwachsene Inhalte lösen diesen Fehler nicht aus.

Ist das 429-Ratenlimit pro Konto oder pro Schlüssel?

Das Limit gilt pro API-Schlüssel: 300 Anfragen pro Minute. Da jedes Konto nur einen Schlüssel hat, müssen mehrere Dienste, die denselben Schlüssel teilen, das Limit gemeinsam einhalten.

Fülle einfach das Formular aus, um deinen Schlüssel zu erhalten

Erstelle ein Konto, kopiere den Schlüssel und passe die Base URL an. Die Konfiguration ist so einfach.