Errori
Ogni codice applicativo, cosa significa e quali errori vale la pena ritentare.
Quando una chiamata non va a buon fine, la risposta ti dà un numero (code) che indica il tipo di problema e una frase (msg) pensata per una persona. Decidi in base al numero; mostra o registra la frase.
L’involucro
{ "code": 40201, "msg": "Insufficient balance", "request_id": "req_…" }codeè un codice applicativo.200significa successo; tutto il resto è elencato qui sotto.- In caso di errore non c’è il campo
data, tranne per alcuni errori della libreria di asset che aggiungonodata.reason. - Anche lo stato HTTP è impostato (
40201arriva con HTTP402). Decidi in base a uno dei due, senza mescolarli: ti consigliamocode, più preciso. request_idè anche nell’headerX-Request-Id. Indicalo quando contatti l’assistenza.
Se una risposta non è proprio JSON — una pagina HTML o di testo dalla rete intermedia —, gestiscila in base allo stato HTTP e registra l’inizio del corpo.
Lingua dei messaggi di errore
msg e l’errorMessage di un’attività fallita sono in inglese per impostazione predefinita. Invia Accept-Language con en, ja, ko, de, fr, es, pt-BR, ru, it o pl, oppure imposta la lingua degli errori API nella console, per riceverli in quella lingua; le altre tornano all’inglese. Le risposte di errore riportano Content-Language. I codici non cambiano mai con la lingua: un motivo in più per non analizzare mai msg.
Quando un modello indica un motivo preciso per il fallimento (per esempio un’immagine di riferimento illeggibile), errorMessage lo riporta in inglese, senza dettagli interni.
Codici generali
code | HTTP | Significato | Ritentare? |
|---|---|---|---|
200 | 200 / 202 | Successo | — |
400 | 400 | La richiesta o il suo input non sono validi; msg indica il problema | No — correggi |
40003 | 400 | Un caricamento non corrisponde al suo ticket (dimensione, tipo o contenuto) | No — nuovo ticket, nuovo caricamento |
40004 | 400 | Richiesta valida, ma il modello ora non può gestire questa combinazione di impostazioni | No — cambia l’impostazione citata in msg |
401 | 401 | Chiave mancante, sconosciuta o revocata (dettagli) | No |
403 | 403 | Non consentito (vedi Permessi) | No |
404 | 404 | Non esiste o appartiene a un’altra chiave | No |
409 | 409 | Conflitto con lo stato attuale (quando ritentare) | A volte |
40901 | 409 | Un preventivo è scaduto o il prezzo è cambiato | Richiedi un nuovo preventivo |
413 | 413 | Corpo della richiesta troppo grande | No — carica i media invece di incorporarli |
429 | 429 | Troppe richieste | Sì — dopo Retry-After |
500 | 500 | Qualcosa si è rotto da parte nostra | Sì — con attesa crescente |
503 | 503 | Un servizio di supporto è momentaneamente non disponibile | Sì — dopo Retry-After |
Saldo e tetti
code | HTTP | Significato | Cosa fare |
|---|---|---|---|
40201 | 402 | Crediti insufficienti per la trattenuta di questa attività | Acquista crediti e reinvia |
40202 | 402 | È stato raggiunto un tetto di spesa della chiave | Alzalo nella console API o aspetta l’azzeramento |
Permessi
code | HTTP | Significato | Cosa fare |
|---|---|---|---|
40301 | 403 | Questa chiave non può chiamare questo modello | Aggiungi il modello ai modelli consentiti della chiave |
40302 | 403 | La richiesta arriva da un indirizzo fuori dalla lista di IP consentiti | Aggiungi l’indirizzo o togli la restrizione |
40303 | 403 | Il servizio non è offerto in questa regione | Non si può aggirare |
40310 | 403 | L’indirizzo email dell’account non è ancora verificato | Apri il link nell’email di registrazione; la chiave funziona appena è verificato |
Un semplice 403 con una chiave valida significa che l’account al momento non può usare l’API; contatta l’assistenza con il request_id.
Disponibilità dei modelli
code | HTTP | Significato | Ritentare? |
|---|---|---|---|
50301 | 503 | Il modello ora non può accettare attività | Sì, più tardi — o scegli un altro modello |
40004 | 400 | Il modello funziona, ma non con queste impostazioni | No — cambia l’impostazione |
Nessuno dei due crea un’attività o trattiene crediti.
Codici di errore delle attività
Un’attività accettata che poi fallisce ha state: "failed" e uno di questi valori in errorCode. L’elenco è chiuso: tratta qualsiasi altro valore come upstream_failed.
errorCode | Significato | Ritentare? |
|---|---|---|
invalid_request | Il modello non ha accettato i parametri | No — correggili |
unsupported_combination | Questa combinazione di impostazioni ora non è supportata | No — cambia un’impostazione |
content_rejected | Il modello ha rifiutato questo contenuto | No — cambia il prompt o il riferimento |
invalid_asset | Un file di riferimento non è leggibile o non è più disponibile | Caricalo di nuovo e crea una nuova attività |
rate_limited | Il servizio di generazione era sovraccarico | Sì, con attesa crescente |
upstream_unavailable | La generazione è temporaneamente non disponibile | Sì, tra poco |
generation_failed | La generazione è partita ma non ha prodotto nulla | Forse — lo stesso input spesso fallisce allo stesso modo |
timeout | L’attività ha esaurito il tempo | Forse — prova un output più breve o a risoluzione più bassa |
upstream_failed | Tutto il resto | Sì, con attesa crescente |
Un’attività fallita rilascia la trattenuta e quindi non costa nulla (pochi modelli addebitano i rifiuti per contenuto e lo indicano nella loro pagina). errorMessage spiega il motivo a parole; decidi solo in base a errorCode.
Quando conviene ritentare un 409
| Caso | Ritentare? |
|---|---|
Due richieste con lo stesso Idempotency-Key sono arrivate insieme | Sì, con la stessa chiave, dopo una breve pausa |
L’Idempotency-Key è stato usato per un’altra richiesta o da un’altra chiave | No |
| Un caricamento o un risultato è ancora in elaborazione | Sì, dopo qualche secondo |
jobs/retry su un’attività non ancora conclusa | Sì, quando è definitiva |
jobs/retry su un’attività riuscita | No — crea una nuova attività |
| Un ticket di caricamento o un file caricato è scaduto | No — caricalo di nuovo |
Scrivere il nuovo tentativo
Ritenta solo ciò che può riuscire al secondo tentativo, aspetta Retry-After quando c’è e altrimenti aumenta l’attesa in modo esponenziale:
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")Quando ritenti createTask, invia sempre lo stesso Idempotency-Key, così una richiesta che in realtà era riuscita non viene eseguita né addebitata due volte.
Diagnosi
- Annota
request_idecode. - Cerca l’attività nei log della console API, per ID attività o
request_id. - Ancora bloccato? Contatta l’assistenza con
request_id, ora (UTC) ecode. Non inviare mai la tua chiave API.

