Fehler
Jeder Geschäftscode, was er bedeutet und welche Fehler eine Wiederholung lohnen.
Wenn ein Aufruf schiefgeht, liefert die Antwort eine Zahl (code), die sagt, welche Art Problem es ist, und einen Satz (msg) für Menschen. Verzweige nach der Zahl; den Satz zeigst oder loggst du.
Die Antworthülle
{ "code": 40201, "msg": "Insufficient balance", "request_id": "req_…" }codeist ein Geschäftscode.200heißt Erfolg, alles andere steht unten.- Bei Fehlern gibt es kein
data-Feld – außer bei einigen Fehlern der Asset-Bibliothek, diedata.reasonmitliefern. - Auch der HTTP-Status ist gesetzt (
40201kommt mit HTTP402). Verzweige nach einem der beiden, nicht nach einer Mischung – wir empfehlen das genauerecode. request_idsteht auch im HeaderX-Request-Id. Gib sie an, wenn du den Support kontaktierst.
Ist eine Antwort gar kein JSON – etwa eine HTML- oder Textseite aus dem Netz dazwischen –, behandle sie nach HTTP-Status und logge den Anfang des Bodys.
Sprache der Fehlermeldungen
msg und die errorMessage eines fehlgeschlagenen Tasks sind standardmäßig Englisch. Schick Accept-Language mit en, ja, ko, de, fr, es, pt-BR, ru, it oder pl oder stell die API-Fehlersprache in der Konsole ein, dann kommen sie in dieser Sprache; andere Sprachen fallen auf Englisch zurück. Fehlerantworten tragen Content-Language. Die Codes ändern sich nie mit der Sprache – noch ein Grund, msg niemals zu parsen.
Meldet ein Modell einen konkreten Grund (etwa ein unlesbares Referenzbild), gibt errorMessage diesen Grund auf Englisch weiter, ohne interne Details.
Allgemeine Codes
code | HTTP | Bedeutung | Wiederholen? |
|---|---|---|---|
200 | 200 / 202 | Erfolg | — |
400 | 400 | Anfrage oder input ungültig; msg nennt das Problem | Nein – korrigieren |
40003 | 400 | Ein Upload passt nicht zu seinem Ticket (Größe, Typ oder Inhalt) | Nein – neues Ticket, neu hochladen |
40004 | 400 | Gültige Anfrage, aber das Modell kann diese Kombination gerade nicht bedienen | Nein – die in msg genannte Einstellung ändern |
401 | 401 | Schlüssel fehlt, ist unbekannt oder widerrufen (Details) | Nein |
403 | 403 | Nicht erlaubt (siehe Berechtigungen) | Nein |
404 | 404 | Existiert nicht oder gehört zu einem anderen Schlüssel | Nein |
409 | 409 | Konflikt mit dem aktuellen Zustand (wann wiederholen) | Manchmal |
40901 | 409 | Ein Angebot ist abgelaufen oder der Preis hat sich geändert | Neu anfragen |
413 | 413 | Request-Body zu groß | Nein – Medien hochladen statt einbetten |
429 | 429 | Zu viele Anfragen | Ja – nach Retry-After |
500 | 500 | Bei uns ist etwas kaputtgegangen | Ja – mit Backoff |
503 | 503 | Ein unterstützender Dienst ist kurz nicht erreichbar | Ja – nach Retry-After |
Guthaben und Limits
code | HTTP | Bedeutung | Was zu tun ist |
|---|---|---|---|
40201 | 402 | Nicht genug Credits für die Reservierung dieses Tasks | Credits kaufen, dann erneut senden |
40202 | 402 | Ein Ausgabelimit des Schlüssels ist erreicht | Limit in der API-Konsole anheben oder auf den Reset warten |
Berechtigungen
code | HTTP | Bedeutung | Was zu tun ist |
|---|---|---|---|
40301 | 403 | Dieser Schlüssel darf dieses Modell nicht aufrufen | Modell zur Liste erlaubter Modelle hinzufügen |
40302 | 403 | Anfrage kam von einer Adresse außerhalb der IP-Allowlist | Adresse hinzufügen oder Einschränkung entfernen |
40303 | 403 | Der Dienst wird in dieser Region nicht angeboten | Lässt sich nicht umgehen |
40310 | 403 | Die E-Mail-Adresse des Kontos ist noch nicht bestätigt | Link aus der Anmelde-Mail öffnen; danach funktioniert der Schlüssel sofort |
Ein einfaches 403 bei gültigem Schlüssel heißt, dass das Konto die API gerade nicht nutzen kann; melde dich mit der request_id beim Support.
Verfügbarkeit von Modellen
code | HTTP | Bedeutung | Wiederholen? |
|---|---|---|---|
50301 | 503 | Das Modell nimmt gerade keine Tasks an | Ja, später – oder ein anderes Modell wählen |
40004 | 400 | Das Modell läuft, aber nicht mit diesen Einstellungen | Nein – Einstellung ändern |
Beide erzeugen keinen Task und reservieren keine Credits.
Fehlercodes von Tasks
Ein angenommener Task, der danach scheitert, hat state: "failed" und einen dieser Werte in errorCode. Die Liste ist abgeschlossen: Behandle jeden anderen Wert wie upstream_failed.
errorCode | Bedeutung | Wiederholen? |
|---|---|---|
invalid_request | Das Modell hat die Parameter nicht akzeptiert | Nein – korrigieren |
unsupported_combination | Diese Kombination von Einstellungen wird gerade nicht unterstützt | Nein – eine Einstellung ändern |
content_rejected | Das Modell hat diesen Inhalt abgelehnt | Nein – Prompt oder Referenz ändern |
invalid_asset | Eine Referenzdatei ließ sich nicht lesen oder ist nicht mehr verfügbar | Neu hochladen und einen neuen Task anlegen |
rate_limited | Der Generierungsdienst war ausgelastet | Ja, mit Backoff |
upstream_unavailable | Generierung ist vorübergehend nicht verfügbar | Ja, gleich noch mal |
generation_failed | Die Generierung lief, hat aber nichts geliefert | Vielleicht – dieselbe Eingabe scheitert oft genauso |
timeout | Der Task hatte keine Zeit mehr | Vielleicht – kürzere oder niedriger aufgelöste Ausgabe versuchen |
upstream_failed | Alles andere | Ja, mit Backoff |
Ein gescheiterter Task gibt seine Reservierung frei und kostet also nichts (einige wenige Modelle berechnen inhaltliche Ablehnungen und sagen das auf ihrer Seite). errorMessage erklärt den Grund in Worten; verzweige nur nach errorCode.
Wann sich ein 409 zu wiederholen lohnt
| Fall | Wiederholen? |
|---|---|
Zwei Anfragen mit demselben Idempotency-Key kamen gleichzeitig an | Ja, nach kurzer Pause mit demselben Schlüssel |
Der Idempotency-Key wurde für eine andere Anfrage oder von einem anderen Schlüssel verwendet | Nein |
| Ein Upload oder eine Ausgabe wird noch verarbeitet | Ja, nach ein paar Sekunden |
jobs/retry für einen Task, der noch nicht fertig ist | Ja, sobald er beendet ist |
jobs/retry für einen erfolgreichen Task | Nein – einen neuen Task anlegen |
| Ein Upload-Ticket oder eine hochgeladene Datei ist abgelaufen | Nein – neu hochladen |
Die Wiederholung schreiben
Wiederhole nur, was beim zweiten Mal klappen kann, warte auf Retry-After, wenn es mitkommt, und sonst exponentiell:
const RETRYABLE = new Set([429, 500, 503, 50301]);
async function call(path, init, attempts = 4) {
for (let i = 0; i < attempts; i++) {
const res = await fetch(`https://api.popnow.ai/api/v1${path}`, init);
if (!res.headers.get('content-type')?.includes('json')) {
throw new Error(`HTTP ${res.status}: ${(await res.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} (${body.request_id})`);
const wait = Number(res.headers.get('retry-after')) * 1000 || 2 ** i * 1000 + Math.random() * 500;
await new Promise((r) => setTimeout(r, wait));
}
throw new Error('out of retries');
}import random, time, requests
RETRYABLE = {429, 500, 503, 50301}
def call(method, path, attempts=4, **kwargs):
for i in range(attempts):
res = requests.request(method, f"https://api.popnow.ai/api/v1{path}", timeout=60, **kwargs)
try:
body = res.json()
except ValueError:
raise RuntimeError(f"HTTP {res.status_code}: {res.text[:200]}")
if body["code"] == 200:
return body["data"]
if body["code"] not in RETRYABLE:
raise RuntimeError(f'{body["code"]} {body["msg"]} ({body.get("request_id")})')
retry_after = res.headers.get("retry-after")
time.sleep(float(retry_after) if retry_after else 2**i + random.random() / 2)
raise RuntimeError("out of retries")Wenn du createTask wiederholst, schick immer denselben Idempotency-Key – sonst wird eine Anfrage, die eigentlich durchging, doppelt ausgeführt und doppelt berechnet.
Fehlersuche
- Notiere
request_idundcode. - Such den Task in den Logs der API-Konsole, per Task-ID oder
request_id. - Kommst du nicht weiter? Kontaktiere den Support mit
request_id, Uhrzeit (UTC) undcode. Schick niemals deinen API-Schlüssel.

