spicyapiDokumentation
Referenz
Hauptinhalt

Fehler

Alle Geschäftscodes, HTTP-Statuswerte, passende Maßnahmen und die Frage, welche Wiederholungen helfen.

Bei einem fehlgeschlagenen Aufruf nennt die Antwort zwei Dinge: eine Zahl in code, die die Problemart beschreibt, und einen lesbaren Satz in msg. Diese Seite erklärt jede Zahl und ob ein weiterer Versuch hilft. Für eine schnelle Lösung anhand eines Symptoms beginnen Sie mit Fehlerbehebung.

Die Antwortstruktur

JSON-Antworten der nativen Task-API nutzen dieselben vier umgebenden Felder. Lesen Sie /v1-Kompatibilitätsantworten und SSE nach deren eigenen Protokollen:

{ "code": 200, "msg": "success", "data": { }, "request_id": "req_…" }
  • code ist ein Geschäftscode, kein HTTP-Status. 200 bedeutet Erfolg.
  • Bei Fehler fehlt data; es ist nicht null. Sie erhalten code, msg und request_id. Die eine Ausnahme: Einige Fehler der Asset-Bibliothek fügen data.reason hinzu.
  • msg ist für Menschen gedacht. Wortlaut und Sprache können sich ändern; siehe unten. Richten Sie Ihre Programmlogik nie danach aus, sondern nach code.
  • request_id steht auch im Header X-Request-Id. Nennen Sie ihn bei Problemmeldungen.

Der HTTP-Status wird ebenfalls korrekt gesetzt. Verwenden Sie einen der beiden Werte, aber nur einen: Bei spezifischen Codes unterscheiden sie sich. Unzureichendes Guthaben ergibt etwa code: 40201 und HTTP 402. Vermischte Behandlung übersieht irgendwann einen Fall.

Wir empfehlen code: 404 sagt nur „nicht gefunden“, 40201 dagegen, dass das verfügbare Guthaben nicht reicht.

Nicht jede Antwort ist JSON

Eine nicht als JSON lesbare Antwort, etwa Klartext oder HTML aus unserem Edge-Netzwerk, hat keinen code. Behandeln Sie sie nach HTTP-Status und protokollieren Sie den Beginn des Bodys. Wiederholen Sie 403 nicht blind: Eine regionale Sperre lässt sich durch Wiederholung nicht ändern.

Sprache der Fehlermeldungen

Lesbare Fehlertexte können in Ihrer gewählten Sprache erscheinen. Standard ist Englisch. Nur diese drei Stellen folgen der Auswahl:

  • msg in der Antwortstruktur;
  • errorMessage eines fehlgeschlagenen Tasks in recordInfo und Webhook-Callbacks, mit der unten genannten Ausnahme;
  • error.message in Fehlerobjekten kompatibler Endpunkte im OpenAI-, Anthropic- oder Google-Gemini-Format unter /v1beta.

Unterstützte Sprachcodes: en, ja, ko, de, fr, es, pt-BR, ru, it, pl.

Die Ausnahme: Nennt das Modell selbst einen konkreten Fehlergrund, etwa ein nicht lesbares Referenzbild oder eine Urheberrechtsbeschränkung für generiertes Audio, enthält errorMessage diesen Grund auf Englisch. Interne Details wie Servicenamen, Hosts, URLs und Anfrage-IDs werden entfernt, damit Sie den tatsächlichen Fehler verstehen können. Gründe zum Konto- oder Abrechnungszustand werden nie durchgereicht; stattdessen erhalten Sie unsere eigene Meldung. Content-Language beschreibt weiterhin msg; Ihre Programmlogik richtet sich immer nach errorCode.

Sprache auswählen

Die erste zutreffende Ebene gewinnt:

  1. Anfrageheader Accept-Language, nur für diese Anfrage. Die übliche HTTP-Gewichtung gilt: Wir verwenden die erkannte Sprache mit dem höchsten q-Wert. Regionale Varianten werden zugeordnet, also de-DE zu de und pt-PT zu pt-BR. Chinesisch wird nicht angeboten; chinesische Tags treffen daher nichts und der nächste Kandidat wird geprüft. * bedeutet keine Präferenz.
  2. Kontoeinstellung unter Einstellungen → API-Fehlersprache. Sie gilt für alle Anfragen mit einem API-Key des Kontos ohne erkennbares Accept-Language. Die meisten serverseitigen SDKs und curl senden standardmäßig keinen solchen Header; daher verlassen sich viele Integrationen darauf. Webhook-Callbacks haben keinen Anfrageheader zur Sprachauswahl und folgen immer der Kontoeinstellung.
  3. Andernfalls Englisch.

Fehlerantworten enthalten Content-Language mit der tatsächlich verwendeten Meldungssprache.

Nur der lesbare Text ändert sich

code, errorCode, OpenAI-kompatibles type und code, Gemini-kompatibles code und status sowie alle Feldnamen bleiben in jeder Sprache identisch. Verwenden Sie Codes und analysieren Sie nie den Wortlaut; erfassen Sie code und request_id in Logs und Warnmeldungen.

Beispiel

Derselbe Fehler 40201 für unzureichendes Guthaben erscheint standardmäßig auf Englisch:

Default
HTTP/1.1 402 Payment Required
Content-Language: en

{ "code": 40201, "msg": "Insufficient balance", "request_id": "req_…" }

Fügen Sie den Header Accept-Language: ja hinzu. Der Rest entspricht der Taskerstellung im Schnellstart:

curl -X POST https://api.spicyapi.ai/api/v1/jobs/createTask \
  -H "Authorization: Bearer $SPICY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $SPICY_IDEMPOTENCY_KEY" \
  -H "Accept-Language: ja" \
  --data "$TASK_PAYLOAD"

msg ist nun Japanisch; code bleibt 40201:

Accept-Language: ja
HTTP/1.1 402 Payment Required
Content-Language: ja

{ "code": 40201, "msg": "残高が不足しています", "request_id": "req_…" }

Allgemeine Codes

codeHTTPBedeutungErneut versuchen?
200200Erfolg—
400400Fehlerhafte Anfrage oder ungültige ParameterNein. Korrigieren und erneut senden
40003400Größe, Typ oder Inhalt einer hochgeladenen Datei entspricht nicht den Angaben bei Anforderung der Upload-URLNein. Neue Upload-URL mit korrektem contentType und Größe anfordern, erneut hochladen und Commit durchführen
40004400Anfrage ist gültig, aber das Modell kann diese Einstellungskombination derzeit nicht bedienenNein. In msg genannte Einstellung ändern, etwa Auflösung oder Seitenverhältnis, oder anderes Modell wählen; siehe unten
401401Authentifizierung fehlgeschlagen; msg nennt einen von drei FällenNein. Header oder Key korrigieren
403403Nicht erlaubt. Bei gültigem API-Key ist das Konto eingeschränkt; siehe unten. Eine unbestätigte E-Mail ergibt stattdessen 40310Nein
404404Existiert nicht oder gehört Ihnen nichtNein
409409Konflikt mit aktuellem ZustandManchmal; siehe unten
40901409Preisangebot abgelaufen, Anfrage oder Preis geändertPreis erneut abfragen und bestätigen; angenommene Anfragen mit ursprünglichem Idempotenzschlüssel wiederfinden
413413Anfragebody überschreitet die akzeptierte ServergrößeNein. Body verkleinern oder Medien über den Uploadablauf senden
429429Zu viele AnfragenMeistens. Nach Retry-After warten. Ein bestimmter 429 betrifft nicht die Geschwindigkeit; siehe Ratenbegrenzungen
500500Fehler auf unserer SeiteJa. Mit Abstand erneut versuchen
503503Hilfsdienst für Preisabfragen, Inline-Bildspeicherung oder Medienuploads kurzzeitig nicht verfügbarJa. Vorhandenes Retry-After abwarten und erneut versuchen; bei createTask mit demselben Idempotency-Key. Hält es ohne Retry-After an, folgen Sie msg, etwa öffentliche HTTPS-URL statt Inline-Bild verwenden

503 und 50301 teilen einen HTTP-Status, sind aber verschiedene Geschäftscodes: 503 betrifft einen Hilfsdienst, 50301 das Modell selbst.

Die drei 401-Fälle unterscheiden

Drei unterschiedliche Fehler führen bei der Authentifizierung zu 401 und benötigen verschiedene Lösungen. code bleibt jeweils 401; msg erklärt den Unterschied.

msg auf EnglischTatsächlicher VorgangÄnderung
Missing credentials: send your API key in the Authorization header as "Bearer sk-spicy-..." (an kompatiblen /v1- und /v1beta-Endpunkten: …as "Authorization: Bearer sk-spicy-...", x-api-key, or x-goog-api-key)Anfrage kam ganz ohne Zugangsdaten anIhr Client verwirft den Header. Prüfen Sie Interceptor, Proxy und ob die Umgebungsvariable im laufenden Prozess geladen wurde
API key format is not recognized: keys begin with sk-spicy-Zugangsdaten kamen an, stammen aber nicht von unsSie haben einen Konsolen-Sitzungswert oder Key eines anderen Anbieters eingefügt. SpicyAPI-Keys beginnen mit sk-spicy-; echo "${SPICY_API_KEY:0:9}" muss genau dies ausgeben
Credentials are invalid or expiredKey hat unser Format, existiert aber nicht, wurde widerrufen oder ist abgelaufenPrüfen Sie ihn auf der API-Key-Seite. Bei Widerruf oder Ablauf erstellen Sie einen Ersatz. Wiederholen wird nie zu 200 führen

Der mittlere Fall wird ohne Datenbankabfrage erkannt. Deshalb kann er etwas sagen, was der dritte nicht kann: Die Zeichenfolge konnte nie funktionieren. Die dritte Meldung ist für nicht vorhandene, widerrufene und abgelaufene Keys bewusst identisch, damit die Antwort nicht zur Prüfung existierender Keys genutzt werden kann.

Hier stehen die Zeichenfolgen auf Englisch; msg folgt der beschriebenen Sprachauswahl. Sein Wortlaut ist keine vertragliche Zusage. Verwenden Sie code für die Logik und die Meldung zum Lesen, Anzeigen oder Protokollieren, nicht zum Zeichenfolgenvergleich.

Konto kann die API nicht aufrufen

In beiden Fällen ist der Key gültig; das Konto kann die API noch nicht aufrufen.

40310 bedeutet unbestätigte E-Mail-Adresse. Die Meldung lautet Verify your account email to run models and call the API…:

  1. Öffnen Sie die Konsole. Ein Banner oben weist auf die unbestätigte Adresse hin und kann die Bestätigungsmail erneut senden.
  2. Folgen Sie dem Link in der Bestätigungsmail; prüfen Sie auch den Spamordner.
  3. Wiederholen Sie denselben Aufruf. Ein neuer Key ist nicht nötig.

Die Konsole funktioniert während der API-Sperre weiter, sodass Sie Ihren Verlauf sehen können.

Ein einfaches 403 mit This account cannot call the API right now bedeutet ein eingeschränktes Konto. Kontaktieren Sie den Support mit request_id.

Guthaben und Limits

codeHTTPBedeutungMaßnahme
40201402Guthaben deckt die geschätzten Kosten nichtUnter Abrechnung in der Konsole aufladen; siehe Kontoeinrichtung. GET /api/v1/chat/credit prüfen
40202402Ausgabenlimit erreichtmsg zeigt welches. Keylimit mit This key has reached its …: Auf API-Key-Seite erhöhen oder Zurücksetzung abwarten. Teamlimit mit Workspace … budget has been reached: Teaminhaber, Administrator oder Budgetverantwortlichen um Erhöhung auf der Teamseite bitten. Plattformlimit mit Platform quota for today is exhausted…: Nicht selbst änderbar; nach 00:00 UTC erneut versuchen. Tageslimits starten um 00:00 UTC, Monatslimits am 1. um 00:00 UTC neu; Gesamtlimits werden nie zurückgesetzt

Keinen der beiden Fehler behebt bloßes Wiederholen. Guthaben und Limits ändern sich nicht durch erneute Anfrage. Siehe Ausgabenlimits.

Berechtigungen

codeHTTPBedeutungMaßnahme
40301403Dieser Key darf das Modell nicht aufrufenModellfreigabeliste des Keys in der Konsole erweitern
40302403Quelladresse fehlt in der IP-FreigabelisteHinzufügen oder IP-Beschränkung dieses Keys entfernen
40303403Dienst wird in dieser Region nicht angebotenNicht umgehbar; siehe verfügbare Regionen
40310403E-Mail des Kontos noch nicht bestätigt; Modelle können nicht ausgeführt werdenLink in Registrierungsmail öffnen oder neue Mail aus der Konsole senden. Nach Bestätigung funktioniert der Key ohne weitere Änderung

Keiner dieser Fehler lässt sich durch Wiederholung lösen.

Ursachencodes der Asset-Bibliothek

Fehler an den Endpunkten der Asset-Bibliothek (/api/v1/assets…) können dem üblichen Umschlag ein maschinenlesbares Feld hinzufügen, data.reason:

{ "code": 400, "msg": "…", "data": { "reason": "asset_library_locked" }, "request_id": "req_…" }

code, HTTP-Status, msg und der Task-errorCode sind mit oder ohne Grund gleich, bestehende Behandlung funktioniert also weiter. Der Grund erscheint nur an den Endpunkten der Asset-Bibliothek, nie an anderen nativen Endpunkten, und die OpenAI-kompatible und andere Kompatibilitätsschichten behalten ihre eigenen Fehlerformen. Die Liste kann wachsen: Behandeln Sie einen unbekannten Wert wie einen fehlenden Grund.

data.reasonHTTPBedeutungWas zu tun ist
asset_library_locked400Die Asset-Bibliothek wird mit der ersten Aufladung freigeschaltetLaden Sie auf. Bereits gespeicherte Assets bleiben nutzbar
asset_library_full400Das Speicherkontingent (Anzahl oder Bytes) ist vollLöschen Sie Assets oder wechseln Sie in einen höheren Plan; GET /api/v1/assets/usage zeigt den nächsten
asset_file_too_large400Die Datei überschreitet das Limit pro Datei des PlansVerwenden Sie eine kleinere Datei oder wechseln Sie in einen höheren Plan
asset_daily_limit429Die tägliche Anzahl neuer Assets ist erreichtWarten Sie bis 00:00 UTC und beachten Sie Retry-After
asset_storage_full503Der Speicher der gesamten Plattform ist vollVersuchen Sie es später erneut
asset_permission_denied403Ihre Teamrolle erlaubt diese Änderung nichtBitten Sie einen Team-Inhaber oder Admin, oder verwenden Sie einen Key, dessen Ersteller eine Rolle mit dieser Berechtigung hat
asset_workspace_forbidden403Dieser Key erreicht diese Bibliothek nicht, zum Beispiel weil das Mitglied, das den Team-Key erstellt hat, das Team verlassen hatErstellen Sie einen neuen Key im benötigten Workspace
asset_entity_name_taken409Die Bibliothek hat bereits eine Figur mit diesem Namen (ohne Beachtung von Groß- und Kleinschreibung). Figuren benennen Sie auf der Seite Assets der Web-App; die schreibgeschützte API zeigt sie derzeit nicht anWählen Sie einen anderen Namen

Modellverfügbarkeit

codeHTTPBedeutungErneut versuchen?
50301503Modell derzeit nicht verfügbarJa. Später versuchen oder anderes Modell wählen
50302503Textanfrage mit oder ohne Streaming scheiterte am Modell vor Antwortauslieferung; Reservierung wurde zurückgegebenJa. Mit neuem Idempotency-Key erneut senden
40004400Modell läuft, jedoch nicht mit diesen EinstellungenNein. Die in msg genannte Einstellung ändern

50301 bedeutet, dass das Modell den Task bei Einreichung nicht annehmen konnte: Es ist nicht gelistet, hat keinen aktiven Preis oder derzeit keine Generierungskapazität. Vorübergehende Kapazitätsprobleme können begrenzte Wiederholungen lösen. Ein nicht verfügbares Modell oder fehlender aktiver Preis wird durch wiederholte Anfragen nicht repariert. Aktualisieren Sie den Katalog und holen Sie vor einem Modellwechsel die Bestätigung des Nutzers ein.

40004 und 50301 unterscheiden sich bewusst. Bei 50301 kann das Modell derzeit keinen Task annehmen; Warten kann helfen. Bei 40004 arbeitet das Modell, kann aber diese Kombination nicht bedienen. msg nennt die Einstellung in Klammern, etwa This model cannot serve this parameter combination right now (…). Warten hilft nicht, eine Wertänderung schon. Keiner der beiden Fälle erstellt einen Task oder reserviert Geld.

Generierungsfehler nach Annahme erscheinen als state: failed

Scheitert die Generierung nach Rückgabe einer Task-ID durch createTask, zeigt recordInfo den Zustand state: "failed" mit errorCode / errorMessage. Die Reservierung wird normalerweise vollständig freigegeben, außer bei ausdrücklich auf der Modellseite als kostenpflichtig genannten Inhaltsablehnungen. Wird die Situation von 40004 erst nach Annahme erkannt, erscheint sie als errorCode: "unsupported_combination". Ergänzen Sie keine synchronen Geschäftscodefälle, die auf dieser Seite nicht vorkommen.

Fehlercodes eines Tasks

Fehler nach Taskannahme stehen in errorCode von recordInfo. Die Menge ist abgeschlossen: Interne Diagnosen erscheinen hier nie. Behandeln Sie unbekannte Werte wie upstream_failed.

errorCodeBedeutungErneut versuchen?
invalid_requestParameter nicht akzeptiertNein. Korrigieren und neu einreichen
unsupported_combinationKombination derzeit nicht unterstütztNein. Andere Einstellungen wählen
content_rejectedGewähltes Modell lehnt den Inhalt ab. SpicyAPI selbst prüft Anfragen nicht; siehe Inhalte und NutzungsverantwortungNein. Prompt ändern oder anderes Modell wählen
rate_limitedGenerierungsdienst ausgelastetJa. Mit Abstand erneut versuchen
upstream_unavailableGenerierung vorübergehend nicht verfügbarJa. In Kürze erneut versuchen
invalid_assetReferenzdatei nicht mehr verfügbarNicht als Retry. retry verwendet ursprüngliche Eingabe; Datei neu hochladen und Task mit neuer URI erstellen
generation_failedGenerierung startete und erzeugte nichtsVielleicht. Gleiche Eingaben scheitern meist gleich
timeoutTask überschritt seine Frist ohne AbschlussVielleicht. Kürzere Dauer oder geringere Auflösung versuchen
upstream_failedSammelcode für andere FehlerJa. Mit Abstand erneut versuchen

Fehlgeschlagene oder abgelaufene Tasks geben normalerweise die gesamte Reservierung frei. Bestimmte Inhaltsablehnungen werden nur bei ausdrücklich auf der Modellseite genannter Ausnahme zum angenommenen Angebotspreis berechnet. Prüfen Sie settled und cost für die endgültigen Kosten. errorMessage ist für Menschen: Es beschreibt den Grund, kann den modellseitigen Grund auf Englisch wiedergeben, siehe oben, und sein Wortlaut ändert sich. Verwenden Sie ausschließlich errorCode für Ihre Logik. „Erneut versuchen“ bedeutet hier einen neuen Task, der bei Erfolg erneut berechnet wird.

Welche Fehler Geld kosten

Taskzustand und Verbindungszustand sind verschiedene Tatsachen

Ausdrücklich abgelehnte Erstellungen, abgelaufene Tasks und historische Abbruchdatensätze verursachen keine Generierungskosten. Fehlgeschlagene Tasks sind normalerweise kostenlos, außer bei bestimmten ausdrücklich als kostenpflichtig genannten Inhaltsablehnungen. Ein Clienttimeout oder Verbindungsabbruch ist kein Taskfehler. Angenommene Tasks sind nicht abbrechbar: Finden Sie den ursprünglichen Task wieder und prüfen Sie Endzustand und Abrechnung. Ein unterbrochener Textstream kann berechnet werden, wenn gültige Nutzung bereits erfasst wurde.

SituationKostenpflichtig?
API lehnt createTask ausdrücklich ohne Taskerstellung ab, etwa mit 40201, 40202, 40004 oder 50301Nein. Erstellung und Reservierung erfolgen in einer Transaktion; Gatewayfehler oder fehlende Antwort beweisen keine Ablehnung
Einreichung läuft in Timeout, Tab wird geschlossen oder Verbindung bricht abNoch unbekannt. Annahme mit ursprünglichem Idempotenzschlüssel wiederfinden; nicht als kostenlosen Retry behandeln
createTask liefert 202, später failed / expiredNormalerweise kostenlos. Bestimmte failed / content_rejected-Ergebnisse kosten den angenommenen Angebotspreis, wenn die Modellseite dies ausdrücklich nennt. settled und cost lesen
Historischer Task mit canceledNein. Kompatibilitätszustand, keine derzeit verfügbare Aktion
createTask liefert 202, Task ist succeededJa, tatsächliche Nutzung bis höchstens zur angenommenen Reservierung. Rest wird freigegeben; keine darüber hinausgehende Nachbelastung
Beliebiger Fehler aus recordInfo, chat/credit oder common/*Nein. Diese Endpunkte kosten nie Geld
Ratenbegrenzung 429 oder Deduplizierung durch IdempotenzschlüsselNein. Erster Fall wurde nicht angenommen; zweiter liefert den einmal berechneten ursprünglichen Task

Abrechnung oder Freigabe endet automatisch, auch nach Prozessunterbrechung. Gewöhnliche Fehler geben die gesamte Reservierung frei; bestimmte ausdrücklich auf der Modellseite genannte Inhaltsablehnungen werden zum angenommenen Angebotspreis berechnet. Prüfen Sie Taskabrechnung und Guthaben für das Ergebnis; siehe Abrechnung.

Wann Wiederholung bei 409 hilft

FallErneut versuchen?
Seltener gleichzeitiger createTask-Konflikt mit gleichem Schlüssel und unveränderten NutzdatenJa. Einige hundert Millisekunden warten und mit demselben Schlüssel wiederholen; siehe Idempotenz
Schlüssel wurde bereits für andere Nutzdaten oder anderen API-Key verwendetNein. Anhalten und Zuordnung des Schlüssels korrigieren; Wiederholung ändert keinen Konflikt
Inline-Bilder oder Upload-Commit werden noch verarbeitet, eventuell mit Retry-AfterJa. Retry-After oder einige Sekunden abwarten und mit demselben Idempotency-Key senden
Kontopreise oder Konfiguration änderten sich während der AnfrageJa. Bei Nutzung von Angeboten Preis erneut abfragen, dann neu senden
Datei wird noch kopiertJa. Einige Sekunden warten und Downloadlink erneut abfragen
jobs/retry für noch nicht abgeschlossenen oder noch nicht abgerechneten TaskJa, später. Auf Endzustand und settled gleich true des ursprünglichen Tasks warten
jobs/retry für erfolgreichen Task oder bereits nach Aufbewahrungsfrist gelöschte EingabeNein. Mit createTask neuen Task erstellen
Upload-URL oder hochgeladene Datei abgelaufenNein. Datei erneut hochladen

Wiederholungslogik schreiben

Wiederholen Sie nicht blind

400, 401, 40004, 40201 und ähnliche Eingabe- oder Berechtigungsfehler liefern bei jedem Versuch dieselbe Antwort. Alle oben mit „Nein“ markierten Versuche sind unnötig und verbrauchen Ihr eigenes Anfragekontingent.

Exponentiell wachsende Wartezeiten mit zufälliger Streuung verhindern, dass viele fehlgeschlagene Anfragen im selben Moment zurückkehren:

JavaScript
// 409 is operation-specific and must be handled at the call site.
const RETRYABLE = new Set([429, 500, 503, 50301]);

async function callWithRetry(path, init, { attempts = 4 } = {}) {
  for (let i = 0; i < attempts; i++) {
    const res = await fetch(`https://api.spicyapi.ai/api/v1${path}`, init);

    // A page from the edge network is not our JSON envelope
    if (!res.headers.get('content-type')?.includes('json')) {
      const text = await res.text();
      throw new Error(`HTTP ${res.status}, not JSON: ${text.slice(0, 200)}`);
    }
    const body = await res.json();

    if (body.code === 200) return body.data;
    if (!RETRYABLE.has(body.code)) {
      throw new Error(`${body.code} ${body.msg} (request_id=${body.request_id})`);
    }

    // When the server says how long to wait, trust it
    const retryAfter = Number(res.headers.get('retry-after'));
    const backoff = Number.isFinite(retryAfter) && retryAfter > 0
      ? retryAfter * 1000
      : 2 ** i * 1000 + Math.random() * 500;

    await new Promise((r) => setTimeout(r, backoff));
  }
  throw new Error('out of retries');
}
Python
import random, time, requests

# 409 is operation-specific and must be handled at the call site.
RETRYABLE = {429, 500, 503, 50301}
BASE = "https://api.spicyapi.ai/api/v1"


def call_with_retry(method: str, path: str, attempts: int = 4, **kwargs) -> dict:
    for i in range(attempts):
        res = requests.request(method, f"{BASE}{path}", **kwargs)

        # A page from the edge network is not our JSON envelope
        try:
            body = res.json()
        except ValueError:
            raise RuntimeError(f"HTTP {res.status_code}, not JSON: {res.text[:200]}")

        if body["code"] == 200:
            return body["data"]
        if body["code"] not in RETRYABLE:
            raise RuntimeError(f'{body["code"]} {body["msg"]} (request_id={body.get("request_id")})')

        # When the server says how long to wait, trust it
        retry_after = res.headers.get("retry-after")
        backoff = float(retry_after) if retry_after else 2**i + random.random() * 0.5
        time.sleep(backoff)

    raise RuntimeError("out of retries")
Go
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"strconv"
	"time"
)

// retryable lists the codes worth another attempt. Anything else returns
// the same answer however many times you ask — and each ask eats your own
// rate limit.
// Whether the generation itself failed is read from recordInfo's state.
var retryable = map[int]bool{429: true, 500: true, 503: true, 50301: true}

type envelope struct {
	Code      int             `json:"code"`
	Msg       string          `json:"msg"`
	Data      json.RawMessage `json:"data"`
	RequestID string          `json:"request_id"`
}

func callWithRetry(newReq func() (*http.Request, error), attempts int, out any) error {
	for i := 0; i < attempts; i++ {
		req, err := newReq()
		if err != nil {
			return err
		}
		res, err := http.DefaultClient.Do(req)
		if err != nil {
			// Transport-level failure: the request may well have arrived.
			// On createTask, send the same Idempotency-Key or this retry
			// turns into a second generation and a second charge.
			time.Sleep(backoff(i, ""))
			continue
		}

		var env envelope
		decErr := json.NewDecoder(res.Body).Decode(&env)
		io.Copy(io.Discard, res.Body)
		res.Body.Close()
		if decErr != nil {
			// Not our JSON envelope, for example a page from the edge network.
			return fmt.Errorf("HTTP %d, response is not JSON: %w", res.StatusCode, decErr)
		}

		if env.Code == 200 {
			return json.Unmarshal(env.Data, out)
		}
		if !retryable[env.Code] {
			return fmt.Errorf("%d %s (request_id=%s)", env.Code, env.Msg, env.RequestID)
		}
		// When the server says how long to wait, trust it
		time.Sleep(backoff(i, res.Header.Get("Retry-After")))
	}
	return fmt.Errorf("out of retries")
}

// backoff trusts Retry-After when present, otherwise backs off
// exponentially with jitter so a batch of failures does not come back
// as one thundering herd.
func backoff(attempt int, retryAfter string) time.Duration {
	if s, err := strconv.Atoi(retryAfter); err == nil && s > 0 {
		return time.Duration(s) * time.Second
	}
	base := time.Duration(1<<attempt) * time.Second
	return base + time.Duration(rand.Intn(500))*time.Millisecond
}

Senden Sie beim Wiederholen von createTask immer denselben Idempotency-Key. Sonst führt „eigentlich erfolgreich, nur die Antwort verloren“ zu doppelter Generierung und Belastung.

Fehlersuche

Wenn ein Fehler unverständlich ist, gehen Sie diese Liste durch:

  1. request_id: Damit können wir die genaue Anfrage finden.
  2. code: Prüfen Sie die Tabellen oben.
  3. Logs in der Konsole: Task-ID oder request_id im Suchfeld unter Logs öffnet den Task mit Status, Kosten, Latenz, verwendendem Key, Fehlercode und Grund. Parameter und Ergebnisse erscheinen nur während ihrer Aufbewahrung; im Team nur für Rollen mit Leseberechtigung für Inhalte.

msg für 500 bleibt eine allgemeine Meldung „Dienst vorübergehend nicht verfügbar“ ohne interne Details. Interne Struktur, Komponentennamen und Stacktraces erscheinen nie in einer Antwort; sie lassen sich nur über request_id verfolgen.

Öffnen Sie unter Support eine Unterhaltung oder schreiben Sie an support@spicyapi.ai. Nennen Sie request_id oder Task-ID, Zeit in UTC und code. Senden Sie niemals einen API-Key.

Auf dieser Seite