PortModels
Log in

Errors

The error envelope, every status code the API returns, and how to handle each.

Envelope#

Errors return a JSON body with a single error object:

json
{
  "error": {
    "message": "model is required",
    "type": "invalid_request_error"
  }
}

Validation failures add an errors field with per-field detail:

json
{
  "error": {
    "message": "validation_failed",
    "type": "invalid_request_error",
    "errors": { "messages": "is required" }
  }
}

Status codes#

StatusTypeCauseHandling
400invalid_request_errorMissing or malformed field, unsupported parameter, insufficient creditsFix the request; don't retry unchanged
401invalid_request_errorMissing, malformed, unknown, or revoked credentialRe-authenticate; for a Connect token, reconnect
403invalid_request_errorAccess denied — missing scope, or a model outside allowed_modelsRequest the scope, or change the model
404not_foundUnknown path or modelCheck the URL and model key
413File upload over 10MBSplit or compress before uploading
429rate_limit_errorRate limitedBack off; honor Retry-After

For persistent errors, contact support with the response's log_id, if present, the model key, and the time of the request.

Common messages#

MessageMeaning
model is requiredNo model in the body
messages must be a listmessages missing or not an array
prompt is requiredImage generation without a prompt
Token is missing the models.run scopeConnect token can't run models
Invalid or revoked connection tokenThe user disconnected your app
Invalid API keyUnknown, revoked, or a suspended account
Rate limit exceededToo many requests from this IP

Retry policy#

SituationRetry?
429Yes — after Retry-After, with exponential backoff
Timeout or 5xxYes — a small number of times, with backoff
400No — the request is wrong
401No — get a new credential first
403No — the permission has to change
js
async function withRetry(fn, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    const res = await fn();
    if (res.status !== 429 && res.status < 500) return res;
    const retryAfter = Number(res.headers.get('retry-after')) || 2 ** i;
    await new Promise(r => setTimeout(r, retryAfter * 1000));
  }
  throw new Error('Exhausted retries');
}

Insufficient credits#

When a user's balance can't cover a request, the request is rejected before the model runs — the balance is never left negative. Surface this to the user as "add credits", not as a generic failure. See Credits.