Published on

Claude-API: Fehler behandeln statt pauschal abfangen

Authors

Fehlerbehandlung bei der Claude-API

TL;DR

Das SDK wiederholt Verbindungsfehler, 408, 409, 429 und alles ab 500 automatisch — zweimal, mit steigendem Abstand. Was Sie selbst behandeln müssen, ist die Unterscheidung zwischen wiederholbar und aussichtslos. Ein pauschales except wirft genau diese Information weg.


Die Fehlerübersicht

CodeTypWiederholbarHäufige Ursache
400invalid_request_errorneinUngültige Anfrage oder Parameter
401authentication_errorneinSchlüssel fehlt oder ist ungültig
403permission_errorneinFehlende Berechtigung
404not_found_errorneinFalsche Modell-ID oder Endpunkt
413request_too_largeneinAnfrage über der Größengrenze
429rate_limit_errorjaKontingent überschritten
500api_errorjaServerseitiges Problem
529overloaded_errorjaDienst vorübergehend überlastet

Die Kette statt des Sammelfangs

Ordnen Sie von der spezifischsten Klasse zur allgemeinsten und behandeln Sie jede Kategorie unterschiedlich:

import anthropic

try:
    antwort = client.messages.create(...)

except anthropic.NotFoundError:
    # 404 — falsche Modell-ID. Wiederholung sinnlos.
    log.error("Modell-ID prüfen")
    raise

except anthropic.RateLimitError as e:
    # 429 — der Kopf sagt, wie lange zu warten ist
    wartezeit = int(e.response.headers.get("retry-after", "60"))
    time.sleep(wartezeit)

except anthropic.APIStatusError as e:
    # jede andere Antwort außerhalb 2xx
    if e.status_code >= 500:
        wiederholen()          # 500, 529 — vorübergehend
    else:
        log.error(f"{e.status_code}: {e.message}")
        raise                  # 4xx — die Anfrage stimmt nicht

except anthropic.APIConnectionError:
    # Netzfehler, bevor eine Antwort kam
    wiederholen()

In Python ist APIConnectionError ein Geschwister von APIStatusError; in TypeScript ist es eine Unterklasse von APIError und muss deshalb vor ihr geprüft werden. In Go gibt es eine einzige Fehlerklasse — dort packen Sie mit errors.As aus und verzweigen über StatusCode.

Für feinere Unterscheidungen als der Statuscode gibt es .type: Damit trennen Sie etwa einen Abrechnungsfehler von einer fehlenden Berechtigung, die beide als 403 kommen.

Die Modell-400er

Ein Fehler 400 heißt normalerweise "die Anfrage ist falsch gebaut". Bei neueren Modellen heißt er häufiger "dieser Parameter existiert nicht mehr". Die Fälle, die bei einer Migration systematisch auftreten:

ParameterAuf welchen Modellen 400
temperature, top_p, top_kClaude Opus 5, Fable 5, Opus 4.8, Opus 4.7
thinking: {type: "enabled", budget_tokens: N}dieselben — ersetzt durch {"type": "adaptive"}
Vorbelegung der letzten Assistenten-NachrichtClaude Opus 5, Fable 5, die 4.6er-Familie
thinking: {type: "disabled"} mit effort xhigh/maxClaude Opus 5
thinking: {type: "disabled"} überhauptClaude Fable 5

Und der unangenehmste, weil er nicht nach einem Anfrageproblem aussieht: Bei Claude Fable 5 scheitert jede Anfrage mit 400, wenn die Datenaufbewahrung Ihrer Organisation unter 30 Tagen liegt — auch bei vollkommen gültigem Anfragekörper. Wenn ein Modell durchgängig mit 400 antwortet und andere funktionieren, prüfen Sie die Organisationskonfiguration, bevor Sie den Prompt debuggen. Details im Beitrag zur Datenaufbewahrung.

Die Zeitüberschreitungsfalle

Zwei Dinge, die regelmäßig überraschen.

Die Einheit unterscheidet sich je SDK. Python und Ruby erwarten Sekunden, TypeScript Millisekunden. Ein aus Python übernommenes timeout: 30 bedeutet in TypeScript 30 Millisekunden — und dann scheitert alles, ohne dass die Ursache offensichtlich wäre.

Zeitüberschreitungen werden wiederholt. Die tatsächliche Wanduhrzeit kann deshalb timeout × (max_retries + 1) erreichen. Bei der Voreinstellung von 10 Minuten und zwei Wiederholungen sind das bis zu 30 Minuten für einen Aufruf, den Sie für begrenzt hielten.

Wenn Sie eine harte Obergrenze brauchen, setzen Sie beides:

client.with_options(timeout=30.0, max_retries=1).messages.create(...)

Was das SDK schon tut

Bevor Sie eigene Wiederholungslogik bauen: Das SDK wiederholt Verbindungsfehler, 408, 409, 429 und alles ab 500 selbstständig mit steigendem Abstand — voreingestellt zweimal. max_retries=0 schaltet es ab.

Eigene Logik lohnt sich nur, wenn Sie darüber hinaus etwas brauchen: eine Obergrenze über den gesamten Vorgang, ein Ausweichen auf ein anderes Modell, oder eine Sicherung gegen dauerhafte Überlastung.

Zwei Fehlerbilder, die keine sind

stop_reason: "refusal" kommt als HTTP 200 mit leerem Inhalt. Kein Ausnahmefehler, kein Statuscode — Code, der ungeprüft auf content[0] zugreift, bricht trotzdem. Die Behandlung steht im Beitrag zu Ablehnungen.

stop_reason: "max_tokens" ist ebenfalls eine erfolgreiche Antwort — nur abgeschnitten. Prüfen Sie stop_reason grundsätzlich, bevor Sie eine Antwort weiterverarbeiten.

Und stop_details ist nur bei einer Ablehnung befüllt; bei allen anderen Abbruchgründen ist es null. Wer ungeprüft darauf zugreift, produziert einen Fehler in der Fehlerbehandlung.

Häufig gestellte Fragen

Wiederholt das Anthropic-SDK Fehler automatisch?

Ja — Verbindungsfehler, 408, 409, 429 und alles ab 500 werden mit steigendem Abstand wiederholt, voreingestellt zweimal. Eigene Wiederholungslogik brauchen Sie nur für darüber hinausgehende Anforderungen wie eine Gesamtobergrenze oder ein Ausweichen auf ein anderes Modell.

Welche Fehler sollte ich nicht wiederholen?

Alle 4xx außer 429: 400 bedeutet eine ungültige Anfrage, 401 einen ungültigen Schlüssel, 403 eine fehlende Berechtigung, 404 eine falsche Modell-ID, 413 eine zu große Anfrage. Eine Wiederholung ändert daran nichts und verbraucht nur Zeit und Kontingent.

Warum scheitern alle Anfragen an einem Modell mit Fehler 400?

Wenn andere Modelle funktionieren, liegt es meist nicht am Anfragekörper. Häufigste Ursachen: ein Parameter, den das neuere Modell nicht mehr kennt — temperature, top_p, top_k oder budget_tokens —, oder bei Claude Fable 5 eine Datenaufbewahrung unter 30 Tagen in der Organisationskonfiguration.

Wie lange kann ein Aufruf tatsächlich dauern?

Bis zu timeout × (max_retries + 1), weil Zeitüberschreitungen wiederholt werden. Bei der Voreinstellung von zehn Minuten und zwei Wiederholungen sind das bis zu 30 Minuten. Für eine harte Obergrenze setzen Sie beide Werte gemeinsam herab.

Warum funktioniert mein Timeout in TypeScript nicht?

Weil die Einheit sich unterscheidet: Python und Ruby erwarten Sekunden, TypeScript Millisekunden. Ein aus einem Python-Beispiel übernommenes timeout: 30 bedeutet in TypeScript 30 Millisekunden, und dann scheitert praktisch jeder Aufruf — mit einer Fehlermeldung, die nicht auf die Ursache zeigt.


Der nächste Schritt

Suchen Sie in Ihrem Code nach einem einzelnen pauschalen except um den Modellaufruf. Ersetzen Sie es durch eine Kette, die mindestens zwischen 429, ab 500 und 4xx unterscheidet — das ist eine halbe Stunde Arbeit und beendet den größten Teil unnötiger Wiederholungen. Wir schauen gern mit drauf.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen