DEVUP Docs
Back to Dashboard

Account & Security

API Error Reference

Every error returned by the DEVUP AI API follows the OpenAI-compatible error format. This page documents every status code, its causes, and how to resolve it.

Standard Error Response Shape

All error responses are JSON objects with a top-level error key. The shape is intentionally compatible with the OpenAI error format so existing SDK error handlers work out of the box.

Response Body
{
  "error": {
    "message": "Human-readable description of the error.",
    "type": "devup_error",
    "code": "machine_readable_error_code"
  }
}
FieldTypeDescription
error.messagestringHuman-readable explanation of the error. Safe to display to end users.
error.typestringAlways "devup_error".
error.codestringMachine-readable error code. Use this for programmatic error handling in your client.

Rate Limit Response Headers

When you receive a 429 rate_limit_exceeded response (your account's rate limit), these headers are included to help you implement backoff logic. Other 429 codes carry Retry-After and the headers listed in their entries below; model_at_capacity also carries retry-after-ms.

HeaderDescription
X-RateLimit-LimitMaximum number of requests allowed in the current window.
X-RateLimit-RemainingNumber of requests remaining in the current window.
X-RateLimit-ResetUnix timestamp (ms) when the current window resets.
Retry-AfterSeconds to wait before retrying the request.
retry-after-msMilliseconds to wait before retrying. Sent with model_at_capacity (5000).

Request IDs

Every response from the /v1 API and from the Anthropic-compatible messages endpoint carries an x-request-id header, on successes and errors alike. It is DEVUP's unique identifier for that request. For billed requests, your dashboard shows the same ID in its Request ID column. Quote it when you contact support at support@devupai.com so the request can be found directly.

To tie a request to your own logs, send an x-client-request-id header with your own ID: 1–64 characters of letters, digits, ., _, : or -. It is echoed back unchanged in the x-client-request-id response header. An x-request-id header you send is treated the same way when x-client-request-id is absent. A value outside that format is not echoed back, and your ID never replaces DEVUP's.

Response Headers
HTTP/2 200
content-type: application/json
x-request-id: req_3f9a1c07b2e64d58a0c9e1f4b7d2a6c3
x-client-request-id: checkout-7f3e
access-control-expose-headers: x-request-id, x-client-request-id, x-devup-warnings

Both headers are listed in Access-Control-Expose-Headers, so browser code can read them from the response.

Error Code Directory

Detailed reference for every error the DEVUP AI API can return.

400

Bad Request

The request payload could not be parsed or is missing required fields. This includes malformed JSON, absent model identifiers, or unsupported parameter values.

Common Causes

  • Request body is not valid JSON (syntax error, trailing comma, unquoted keys).
  • The required "model" field is missing or not a string.
  • Unsupported parameters for the target model (e.g., sending tools to a non-tool-calling model).
  • Invalid value types (e.g., temperature as a string instead of a number).

How to Resolve

  • 1.Validate your JSON payload with a linter before sending.
  • 2.Ensure the "model" field is present and matches a supported DEVUP model identifier.
  • 3.Refer to the model's documentation page for supported parameters.
  • 4.Check Content-Type is set to application/json.
Example 400 Response
{
  "error": {
    "message": "The \"model\" field is required. Example: \"deepseek-ai/DeepSeek-V4-Pro\"",
    "type": "devup_error",
    "code": "missing_model"
  }
}
400

Bad Request: Cache Retention Unsupported

Prompt cache retention was requested with invalid options, with a service tier, or on a model or ttl that does not support it.

Common Causes

  • prompt_cache_options is not {"mode": "explicit", "ttl": "5m" | "1h"}.
  • The model does not offer retention for the requested ttl.
  • The request also sets service_tier.

How to Resolve

  • 1.Check the model page for its Prompt cache retention table.
  • 2.Use a supported ttl, or remove prompt_cache_options.
  • 3.Remove service_tier from requests that use retention.
Example 400 Response
{
  "error": {
    "message": "Prompt cache retention with ttl \"1h\" is not available for this model.",
    "type": "devup_error",
    "code": "cache_retention_unsupported"
  }
}
400

Bad Request: Use Responses API

The requested model or feature is served on /v1/responses rather than Chat Completions. When the request included tools on a model whose tool calling is served on /v1/responses, the message is: Tool calling for this model is served on /v1/responses. Send requests that use tools to /v1/responses; requests without tools work here.

Common Causes

  • The model does not support Chat Completions and is served on /v1/responses.
  • Tool calling for this model is served on /v1/responses, and the request included tools.

How to Resolve

  • 1.Send the request to /v1/responses instead of /v1/chat/completions.
  • 2.For models that support Chat Completions without tools, send requests that use tools to /v1/responses; requests without tools work on /v1/chat/completions.
  • 3.Check the model before sending: tool_calls.chat_completions in GET /v1/models is false when the model's tool calls are served on /v1/responses. The model page shows whether the model or its tool calling requires /v1/responses.
Example 400 Response
{
  "error": {
    "message": "This model is served on /v1/responses and does not support Chat Completions. Send the same request to /v1/responses.",
    "type": "devup_error",
    "code": "use_responses_api"
  }
}
400

Bad Request: Wrong Endpoint for This Model

The model is not served on the endpoint the request was sent to. The message names the endpoint that serves it. The request is refused before any charge is made.

Common Causes

  • An image, speech, video, embedding or reranking model was sent to /v1/chat/completions or /v1/responses.
  • A text model was sent to an image, speech, video or embeddings endpoint.

How to Resolve

  • 1.Send the request to the endpoint named in the message.
  • 2.Or choose a model that this endpoint serves; the model page lists its endpoint.
Example 400 Response
{
  "error": {
    "message": "This model is served on /v1/images/generations, not on /v1/chat/completions. Send the request to /v1/images/generations.",
    "type": "devup_error",
    "code": "wrong_endpoint"
  }
}
400

Unsupported Content

The model does not accept one or more content types in the request, such as audio, images, or video.

Common Causes

  • Audio input was sent to a model that cannot process audio.
  • Non-text content (images, audio, video) was sent to a text-only model.
  • An unexpected or unsupported item type was included in the message content.

How to Resolve

  • 1.Remove audio, image, or video inputs from the request if using a text-only model.
  • 2.Switch to a multimodal model that accepts the desired content type.
Example 400 Response
{
  "error": {
    "message": "This model does not accept audio input.",
    "type": "devup_error",
    "code": "unsupported_content"
  }
}
400

Unsupported Parameter

A request parameter or argument is not supported or recognized by the target model.

Common Causes

  • Passing model-specific parameters not accepted by this model.
  • Sending unrecognized request arguments in the payload.
  • Sending reasoning_effort together with tools on /v1/chat/completions to a model that does not accept the two together.

How to Resolve

  • 1.Remove the unsupported parameter from the request payload.
  • 2.Check the model documentation for the list of supported parameters.
  • 3.For reasoning_effort with tools: set reasoning_effort to "none", remove the tools, or send the request to /v1/responses with reasoning.effort.
Example 400 Response
{
  "error": {
    "message": "A parameter in the request is not supported by this model: seed.",
    "type": "devup_error",
    "code": "unsupported_parameter"
  }
}
400

Context Length Exceeded

The request token count is longer than the model's supported context window. The code and message are the same with or without streaming: a streamed request gets this HTTP 400 before any stream is opened, and it is not billed.

Common Causes

  • The prompt and conversation history contain more tokens than the model's context window.
  • Combined prompt tokens exceed the model's maximum context limit.

How to Resolve

  • 1.Shorten the prompt or trim older messages from the conversation history.
  • 2.Switch to a model with a larger context window.
Example 400 Response
{
  "error": {
    "message": "The request is longer than this model's context window.",
    "type": "devup_error",
    "code": "context_length_exceeded"
  }
}
400

Invalid Request Format

The request payload structure does not match the format or schema expected by the model.

Common Causes

  • The request body does not match the expected schema.
  • A specific field in messages or options is improperly structured.

How to Resolve

  • 1.Check the field indicated in the error message (e.g., messages[0].content).
  • 2.Verify that message objects conform to the standard role and content format.
Example 400 Response
{
  "error": {
    "message": "The request does not match the format this model expects. Check messages[0].content.",
    "type": "devup_error",
    "code": "invalid_request_format"
  }
}
400

Bad Request: Tool Calling Not Supported

The request includes tools, and this model does not support tool calling.

Common Causes

  • tools or tool_choice was sent to a model that answers in text only.

How to Resolve

  • 1.Remove tools and tool_choice from the request.
  • 2.Or choose a model whose page lists tool calling.
  • 3.Retrying the same request returns the same error.
Example 400 Response
{
  "error": {
    "message": "This model does not support tool calling. Remove tools and tool_choice from the request.",
    "type": "devup_error",
    "code": "tools_not_supported"
  }
}
400

Bad Request: Empty Message Content

A message in the conversation has empty content, and this model does not accept empty messages.

Common Causes

  • A message has "content": "" or an empty list of content parts.

How to Resolve

  • 1.Give every message non-empty content, or remove the empty message.
  • 2.Retrying the same request returns the same error.
Example 400 Response
{
  "error": {
    "message": "A message in the request has empty content, which this model does not accept. Give every message non-empty content.",
    "type": "devup_error",
    "code": "empty_message_content"
  }
}
400

Bad Request: Conversation Must End With a User Message

This model only answers a conversation whose last message is a user message.

Common Causes

  • The last message in messages has the role assistant.

How to Resolve

  • 1.End the conversation with a user message.
  • 2.Retrying the same request returns the same error.
Example 400 Response
{
  "error": {
    "message": "This model needs the conversation to end with a user message.",
    "type": "devup_error",
    "code": "conversation_must_end_with_user"
  }
}
400

Bad Request: Feature Not Supported

The request uses a feature that this model does not support.

Common Causes

  • A parameter or input type in the request is not available on this model.

How to Resolve

  • 1.Check the model page for the features it supports, and remove the others from the request.
  • 2.Or choose a model that supports the feature.
  • 3.Retrying the same request returns the same error.
Example 400 Response
{
  "error": {
    "message": "This model does not support a feature used in the request. Check the model page for what it supports.",
    "type": "devup_error",
    "code": "feature_not_supported"
  }
}
400

Bad Request: Structured Output Does Not Match the Schema

The request set response_format json_schema with strict: true, and the model's reply does not match the schema after a second try. The request is not billed.

Common Causes

  • The schema is too complex for this model, or the prompt leads the model away from it.

How to Resolve

  • 1.Retry the request.
  • 2.Simplify the schema, or describe the expected fields in the prompt.
  • 3.Or leave out strict: true to receive the JSON as produced, with the notice structured_output_not_matched.
Example 400 Response
{
  "error": {
    "message": "This model's reply does not match the requested json_schema. The request was not billed. Retry it, or simplify the schema.",
    "type": "devup_error",
    "code": "structured_output_mismatch"
  }
}
400

Bad Request: Response Format Not Supported

The request sets a response_format that this model does not support.

Common Causes

  • response_format is {"type": "json_schema"} or {"type": "json_object"}, and this model does not produce that format.

How to Resolve

  • 1.Remove response_format and describe the JSON you need in the prompt.
  • 2.Or choose a model whose page lists structured output (json_schema) or JSON mode (json_object).
  • 3.Retrying the same request returns the same error.
Example 400 Response
{
  "error": {
    "message": "This model does not support the requested response_format. Remove response_format, or check the model page for the formats it supports.",
    "type": "devup_error",
    "code": "response_format_not_supported"
  }
}
400

Bad Request: Request Rejected by the Model

The model rejected the request, and no more specific code applies. On /v1/inference, this code also means the multipart/form-data body could not be read. A max_tokens, max_completion_tokens or max_output_tokens outside the model's output limit returns invalid_max_tokens instead, except on the Messages-compatible endpoint, POST /anthropic/v1/messages.

Common Causes

  • A message or parameter has a form or value this model does not accept.
  • On /v1/inference, a malformed multipart/form-data body.

How to Resolve

  • 1.Check the messages and parameters against the API reference and the model page.
  • 2.Retrying the same request returns the same error.
Example 400 Response
{
  "error": {
    "message": "The model rejected the request. Check the messages and parameters against the API reference.",
    "type": "devup_error",
    "code": "invalid_request_error"
  }
}
400

Bad Request: Request Cannot Be Bounded Under Scoped Token Budget

A Scoped JWT with a finite DZD budget was used on a request whose maximum cost cannot be determined before execution. The request is rejected before execution and is not billed.

Common Causes

  • Chat messages include non-image media parts (audio, video, or file parts), or exceed the 8-image / 10 MB per-image / 20 MB total image inspection limit when calling with a finite-budget Scoped JWT.
  • Calling a pricing unit or execution mode whose final cost depends on post-execution output duration, token-metered image output, runtime seconds, or webhook completion under a finite-budget Scoped JWT: token-metered image models, prompt-only per-second video generation without a bounded source clip, per-second or asynchronous webhook or binary-output POST /v1/inference/{model} calls, or audio/video uploads with an unrecognized container header.

How to Resolve

  • 1.For vision chat requests with a Scoped JWT, pass PNG, JPEG, WebP, or GIF images via inline data: URLs or public https:// URLs within the 8-image (10 MB each, 20 MB total) limit.
  • 2.For audio transcription (POST /v1/audio/transcriptions), upload WAV, MP3, FLAC, OGG, M4A, MP4, or WebM audio; for per-second video editing (POST /v1/video/generations), upload an MP4, MOV, or WebM source clip or choose a fixed per-video model.
  • 3.For prompt-only per-second video generation, token-metered image models, or per-second / webhook POST /v1/inference/{model} calls, authenticate with an account API key (sk-devup-...).
Example 400 Response
{
  "error": {
    "message": "This request cannot be bounded before execution under a Scoped JWT spending limit. Use a supported bounded model or an account API key.",
    "type": "devup_error",
    "code": "scoped_budget_unbounded_request"
  }
}
401

Unauthorized: Invalid API Key

The request did not include a valid API key, or the provided key has been deactivated or not found.

Common Causes

  • Missing Authorization header entirely.
  • Authorization header does not use the "Bearer" scheme.
  • API key has been rotated or deleted from the dashboard.
  • Using an invalid or corrupted key string.

How to Resolve

  • 1.Set the header as: Authorization: Bearer sk-devup-...
  • 2.Regenerate your API key from Dashboard → API Keys.
  • 3.Ensure there are no trailing whitespace or newline characters in the key.
Example 401 Response
{
  "error": {
    "message": "The API key provided is invalid or has been deactivated.",
    "type": "devup_error",
    "code": "invalid_api_key"
  }
}
401

Unauthorized: Missing API Key

The request did not include an API key, or the provided API key was empty. All API endpoints, including GET /v1/models and GET /v1/models/{model}, require a valid API key. GET /v1/models, GET /v1/models/{model}, GET /v1/me and GET /v1/me/avatar accept the key as Authorization: Bearer <key> or in the x-api-key header; when both are sent, Authorization is used. On these four endpoints the message is: Provide your API key as: Authorization: Bearer sk-devup-..., or in the x-api-key header.

Common Causes

  • The API key was omitted entirely from the HTTP request (including GET /v1/models).
  • The Authorization header was present but lacked the 'Bearer ' prefix or API key token.

How to Resolve

  • 1.Provide your API key in the request header as: Authorization: Bearer sk-devup-...
  • 2.On GET /v1/models, GET /v1/models/{model}, GET /v1/me and GET /v1/me/avatar, the x-api-key: sk-devup-... header is also accepted.
  • 3.Verify that your application's environment variable holding the API key is set and non-empty.
Example 401 Response
{
  "error": {
    "message": "Provide your API key as: Authorization: Bearer sk-devup-...",
    "type": "devup_error",
    "code": "missing_api_key"
  }
}
401

Unauthorized: Scoped Token Expired

The scoped JWT credential has passed its configured expiration timestamp (exp claim).

Common Causes

  • The scoped token TTL duration has elapsed.
  • The client is attempting to reuse an outdated scoped token.

How to Resolve

  • 1.Generate a new scoped token from Dashboard → API Keys.
  • 2.Implement automatic token refresh before the expiration timestamp in your client application.
Example 401 Response
{
  "error": {
    "message": "This scoped token expired at 2026-08-14T10:00:00.000Z.",
    "type": "devup_error",
    "code": "token_expired"
  }
}
401

Unauthorized: Scoped Token Revoked

The scoped JWT credential was explicitly revoked or deactivated by the account owner.

Common Causes

  • The token was revoked via Dashboard → API Keys.
  • The token was deactivated due to security or credential rotation.

How to Resolve

  • 1.Generate a new scoped token from Dashboard → API Keys.
  • 2.Check with the account administrator who issued the credential.
Example 401 Response
{
  "error": {
    "message": "This scoped token has been revoked.",
    "type": "devup_error",
    "code": "token_revoked"
  }
}
402

Payment Required: Insufficient Balance

The authenticated master account lacks sufficient DZD balance to process the request. If the balance is zero or below when the request arrives, the message starts with: Your balance is depleted. Top up at https://devupai.com/dashboard/billing. Otherwise, a model request gets the message: Your balance is insufficient for this request. Top up at https://devupai.com/dashboard/billing.

Common Causes

  • DZD balance is zero or below the estimated cost of the request.
  • Concurrent requests consumed the available pre-paid balance.
  • A request with a non-empty tools array that the balance does not cover in full, including a reply of the requested length (the request's output limit, or the model's default output length, at most its max_output_tokens, when none is sent). Such a request is not shortened to fit the balance. On POST /v1/chat/completions and POST /anthropic/v1/messages, a request without tools is answered with a smaller max_tokens instead, when the balance covers part of the reply (notice max_tokens_capped_by_balance).

How to Resolve

  • 1.Top up your balance via BaridiMob, Edahabia, or CIB at Dashboard → Billing.
  • 2.Check your balance via GET /v1/user/balance or the dashboard before retrying.
  • 3.For a request with tools, you can also send a smaller max_tokens (max_output_tokens on POST /v1/responses).
Example 402 Response
{
  "error": {
    "message": "Your balance is insufficient for this request. Top up at https://devupai.com/dashboard/billing.",
    "type": "devup_error",
    "code": "insufficient_balance"
  }
}
402

Payment Required: Scoped Token Budget Exhausted

Cumulative DZD spend or active concurrent reservations on the scoped token leave insufficient remaining allowance for the request. When cumulative settled spend has already reached the token's budget, the message is: Budget exhausted: <spent> / <budget> DZD spent. When the remaining allowance across active requests is smaller than the request's maximum cost, the message is: The remaining token allowance does not cover this request.

Common Causes

  • Total settled DZD cost of completed requests on this scoped token reached its configured budget.
  • Concurrent in-flight requests using the same scoped token have reserved the remaining DZD allowance, or this request's bounded maximum cost exceeds the remaining allowance.
  • A request with a non-empty tools array, or an explicit output token limit, whose maximum cost exceeds the token's remaining DZD allowance (requests without tools and without an explicit output limit automatically shorten the default output limit when partial allowance remains, returning notice max_tokens_capped_by_budget).

How to Resolve

  • 1.Generate a new scoped token in Dashboard → API Keys → Scoped Tokens when continued access is intended (topping up your account balance does not reset an existing scoped token's spend).
  • 2.Send a smaller max_completion_tokens on POST /v1/chat/completions (or max_output_tokens on POST /v1/responses, max_tokens on POST /anthropic/v1/messages) so individual requests reserve only the output ceiling you need.
  • 3.If other requests sharing this token are still in progress and finish below their reserved ceiling, wait for them to complete before sending another smaller request.
Example 402 Response
{
  "error": {
    "message": "Budget exhausted: 50.00 / 50.00 DZD spent.",
    "type": "devup_error",
    "code": "budget_exhausted"
  }
}
403

Forbidden: Account Suspended

The DEVUP account has been suspended by an administrator. All API requests are blocked.

Common Causes

  • Account flagged for terms of service or security review.
  • Administrative freeze on the account.

How to Resolve

  • 1.Contact DEVUP AI support at support@devupai.com.
Example 403 Response
{
  "error": {
    "message": "Account suspended. Contact support.",
    "type": "devup_error",
    "code": "account_suspended"
  }
}
403

Forbidden: Model Not Allowed

The scoped token is restricted to specific models and does not grant access to the requested model.

Common Causes

  • The requested model is not included in the token's allowed models list.
  • A typo in the requested model identifier when using a restricted scoped token.

How to Resolve

  • 1.Generate a new scoped token that includes the model in Dashboard → API Keys → Scoped Tokens.
  • 2.Change the request payload to specify one of the allowed models listed in the error message.
Example 403 Response
{
  "error": {
    "message": "This scoped token does not grant access to model \"deepseek-ai/DeepSeek-V4-Pro\". Allowed: meta-llama/Llama-3.3-70B-Instruct",
    "type": "devup_error",
    "code": "model_not_allowed"
  }
}
404

Not Found: Model Not Found

The requested model identifier was not found in the catalog. On GET /v1/models/{model}, the message is: The model "<id>" does not exist. List available models with GET /v1/models.

Common Causes

  • The requested model identifier does not exist in the model catalog.
  • GET /v1/models/{model} was called with an identifier that is not in the catalog.

How to Resolve

  • 1.Verify the model identifier against the model catalog (GET /v1/models).
  • 2.Check for typos or casing errors in the model parameter.
Example 404 Response
{
  "error": {
    "message": "The requested model was not found.",
    "type": "devup_error",
    "code": "model_not_found"
  }
}
409

Conflict: Request Outcome Needs Confirmation

A prior request with this request ID has an outcome that needs confirmation before the operation can be repeated.

Common Causes

  • A request with the same identifier is already in progress or awaiting outcome confirmation.

How to Resolve

  • 1.Do not automatically repeat the operation with the same request ID after this response.
  • 2.Keep the x-request-id header value and contact support if you need to confirm the outcome and any recorded usage.
Example 409 Response
{
  "error": {
    "message": "The outcome of this request must be confirmed before it can be repeated. Contact support with the request ID.",
    "type": "devup_error",
    "code": "request_outcome_pending"
  }
}
429

Too Many Requests

Your account's request rate limit was reached. The response carries the X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset and Retry-After headers. When the model itself is at capacity, the code is model_at_capacity.

Common Causes

  • Exceeded ~600 requests per minute (per account).
  • Burst traffic from automated scripts or load tests without throttling.

How to Resolve

  • 1.Implement exponential backoff with jitter in your client.
  • 2.Respect the Retry-After header returned in the response.
  • 3.Use a token-bucket or leaky-bucket algorithm for batch workloads.
Example 429 Response
{
  "error": {
    "message": "Rate limit exceeded. Please slow down your requests and try again shortly.",
    "type": "devup_error",
    "code": "rate_limit_exceeded"
  }
}

Response Headers

Headers
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1790000000000
Retry-After: 12
429

Too Many Requests: Model at Capacity

The model is momentarily at capacity. This is not your account's rate limit, so no X-RateLimit-* headers are sent. On POST /anthropic/v1/messages the same condition returns HTTP 529 with an overloaded_error.

Common Causes

  • Demand on this model is momentarily at its capacity.

How to Resolve

  • 1.Wait for the delay in the Retry-After header (5 seconds) or retry-after-ms (5000), then retry. Retry-After is in seconds and retry-after-ms gives the same delay in milliseconds.
  • 2.The OpenAI and Anthropic SDKs retry this error automatically after the indicated delay.
  • 3.For repeated responses, use exponential backoff with a bounded number of attempts, or choose another model.
Example 429 Response
{
  "error": {
    "message": "This model is currently at capacity. Retry in a few seconds.",
    "type": "devup_error",
    "code": "model_at_capacity"
  }
}

Response Headers

Headers
Retry-After: 5
retry-after-ms: 5000
429

Too Many Requests: Concurrency Limit Exceeded

Too many requests in progress for your account. Wait for in-flight requests to finish, then retry.

Common Causes

  • Your account has as many requests in progress for this model as its per-model limit allows (50 by default).
  • Your account has as many requests in progress across all models as its total limit allows (100 by default).
  • Streaming responses are still open. A streaming request holds its slot until the stream ends.

How to Resolve

  • 1.Wait the number of seconds in the Retry-After header, then retry.
  • 2.Cap the number of requests your client sends in parallel below your limit, for example with a semaphore or a worker pool.
  • 3.Close streams you no longer need.
  • 4.The X-Concurrency-Limit header gives the limit that was reached. To discuss a higher limit, contact support.
Example 429 Response
{
  "error": {
    "message": "Too many concurrent requests for this account. Wait for in-flight requests to finish, then retry.",
    "type": "devup_error",
    "code": "concurrency_limit_exceeded"
  }
}

Response Headers

Headers
Retry-After: 2
X-Concurrency-Limit: 50
429

Too Many Requests: Tokens-per-Minute Limit Exceeded

Your account's tokens-per-minute limit is reached. Retry after the Retry-After interval.

Common Causes

  • The prompt and completion tokens of requests completed in the last 60 seconds reached your account's tokens-per-minute limit.
  • Large prompts or long completions sent in quick succession.
  • This limit applies only to accounts with an agreed tokens-per-minute limit. Requests already in progress always complete; only new requests are rejected.

How to Resolve

  • 1.Wait the number of seconds in the Retry-After header. It gives the time until the current 60-second window ends.
  • 2.Spread large batches over time instead of sending them at once.
  • 3.Reduce prompt size or max_tokens where your use case allows.
  • 4.The X-TPM-Limit header gives your account's limit. To discuss a higher limit, contact support.
Example 429 Response
{
  "error": {
    "message": "Token-per-minute limit reached for this account. Retry after the indicated delay.",
    "type": "devup_error",
    "code": "tpm_limit_exceeded"
  }
}

Response Headers

Headers
Retry-After: 12
X-TPM-Limit: 500000
429

Too Many Requests: Flex Capacity Unavailable

A request using the Flex service tier waited in the admission queue beyond the maximum admission timeout without being admitted.

Common Causes

  • High demand on Flex tier GPUs made admission queue wait times exceed the threshold.
  • Temporary compute constraints on discounted Flex tier hardware.

How to Resolve

  • 1.Retry later when Flex tier GPU capacity opens up.
  • 2.Omit service_tier from the request payload to execute immediately on the Standard tier.
  • 3.Wait for the time in the Retry-After header (60 seconds) before retrying.
Example 429 Response
{
  "error": {
    "message": "Flex capacity is currently unavailable. Retry later, or send the request without service_tier to use the standard tier.",
    "type": "devup_error",
    "code": "flex_capacity_unavailable"
  }
}

Response Headers

Headers
Retry-After: 60
500

Server Error

The request could not be completed. On a streamed Responses request, the stream ends with a response.failed event carrying this code.

Common Causes

  • The model stopped before completing its response.
  • A step of the request on our side, such as saving a generated file, could not be completed.

How to Resolve

  • 1.Retry after a short delay; most of these are temporary.
  • 2.Check the DEVUP status page for ongoing incidents.
  • 3.If it persists, try another model, and contact support with your request ID.
Example 500 Response
{
  "error": {
    "message": "The model could not complete this request. Retry it; retrying usually succeeds.",
    "type": "devup_error",
    "code": "server_error"
  }
}
502

Temporary Model Error

The model returned an empty response, or its response ended before it finished. The request was not billed, and retrying usually succeeds. When the model's response cannot be used at all, the message is: "The model could not complete this request. Retry it; retrying usually succeeds."

Common Causes

  • The model returned an empty response.
  • The model's response ended before it finished, for example a stream that closed before its first event.
  • The model's response to a /v1/audio/speech request did not contain audio.

How to Resolve

  • 1.A request that the model rejects does not return this error: it returns 400 with a specific code, such as tools_not_supported or conversation_must_end_with_user. Only this error is worth retrying.
  • 2.An empty response is retried once automatically before this error is returned.
  • 3.Your account was not billed for this request; the balance hold was released.
  • 4.A stream whose response ends early after output has started stops without this error; it is not billed either. See Streaming, Errors and cancellation.
  • 5.Retry the request after a short delay; retrying usually succeeds.
  • 6.If it persists across retries, check the status page or use another model.
Example 502 Response
{
  "error": {
    "message": "The model returned an empty response. The request was not billed. Retrying usually succeeds.",
    "type": "devup_error",
    "code": "DEVUP_COMPUTE_ERROR"
  }
}
503

Service Unavailable

Requests are paused for a few seconds, for example while request limits cannot be checked or during maintenance.

Common Causes

  • Request limits cannot be checked for a few seconds, so requests are paused rather than let through unchecked.
  • Scheduled maintenance.

How to Resolve

  • 1.Wait for the interval specified in the Retry-After header (typically 5 seconds) before retrying.
  • 2.When the message asks to contact support with the request ID before repeating the request, confirm the prior request's outcome before resending a non-idempotent operation.
  • 3.Implement exponential backoff with jitter in your client library.
  • 4.Check the status page for active platform maintenance notices.
Example 503 Response
{
  "error": {
    "message": "Requests are paused for a few seconds. Retry after the delay in the Retry-After header.",
    "type": "devup_error",
    "code": "service_unavailable"
  }
}

Response Headers

Headers
Retry-After: 5
503

Service Unavailable: Model Unavailable

The requested model is published in the catalog, but cannot currently be served. Retry according to the delay communicated in Retry-After and/or retry-after-ms when present.

Common Causes

  • The requested model is temporarily unreachable or offline.
  • Temporary compute capacity or serving interruption for this specific model.

How to Resolve

  • 1.Honor the retry delay communicated through Retry-After and/or retry-after-ms when present.
  • 2.Implement exponential backoff in your client.
  • 3.Check the model status or switch to an alternative model if the issue persists.
Example 503 Response
{
  "error": {
    "message": "The requested model is temporarily unavailable. Retry shortly.",
    "type": "devup_error",
    "code": "model_unavailable"
  }
}

Response Headers

Headers
Retry-After: 5
retry-after-ms: 5000

More Error Codes

Validation and endpoint-specific errors. None of them is fixed by retrying the same request, except where the action says so.

StatusCodeMeaningWhat to do
405admin_operation_requires_postThis operation requires POST.Send a POST request.
403admin_origin_requiredSubmit this operation from the application.Open the application and submit the request again.
400admin_confirmation_requiredConfirmation is required for this operation.Confirm the intended operation.
Action resultrecovery_authorization_requiredVerify a recovery code before updating your password.Verify a new recovery code.
Action resultpassword_recovery_unavailablePassword recovery could not be completed.Verify a new recovery code and try again.
Action result or noticepassword_recovery_review_requiredPassword recovery requires a review before continuing.Contact support before trying again.
Action noticesession_revocation_requiredThe password is updated; other sessions may remain active.Contact support for a session review.
Action resultpayment_receipt_not_foundNo completed payment receipt matches the reference in your account.Select a completed payment from your billing history.
Action resultreceipt_email_unavailableReceipt sending is temporarily unavailable.Try again shortly.
404network_volume_not_foundThe selected network volume is not available in your account.Select a volume from your account.
400missing_toolstool_choice is "required" or a named function, and tools is missing or empty.Add at least one tool, or use tool_choice "auto" or "none".
400invalid_max_tokensmax_tokens or max_completion_tokens on POST /v1/chat/completions, or max_output_tokens on POST /v1/responses, is not between 1 and the model's output limit, the model's own max_output_tokens value in GET /v1/models. The message names the parameter you sent and the model's limit N, for example: max_output_tokens must be between 1 and N. A max_output_tokens that is not a whole number gets: max_output_tokens must be a whole number between 1 and N.Send a value between 1 and the model's max_output_tokens from GET /v1/models.
404endpoint_not_foundNo endpoint exists at this method and path under /v1/. Example: No endpoint exists at GET /v1/chat.Check the method and path against the API reference.
404avatar_not_foundThe account has no profile picture, on GET /v1/me/avatar. The message is: This account has no profile picture. GET /v1/me then shows avatar: null.Show the initial from GET /v1/me instead. Request the picture again when GET /v1/me returns an avatar object.
403scoped_token_not_allowedGET /v1/me and GET /v1/me/avatar accept account API keys (sk-devup-...) only, and a scoped token was sent. The message is: This endpoint accepts account API keys (sk-devup-...) only, not scoped tokens.Send an account API key from the dashboard.
400payload_too_largemessages has more than 512 entries, or an embeddings input has more than 2,048 entries.Send fewer entries per request.
400invalid_valueA parameter has a value the model does not accept.Check the parameter's allowed values in the API reference.
400missing_required_parameterA parameter the model requires is missing.Add the parameter named in the message.
400permission_deniedThe request was blocked by the safety system.Change the content of the request.
400 or 429insufficient_quotaThe request could not be served because a usage quota was reached.Retry later. If it persists, contact support with the request ID.
400unsupported_destinationThe text model does not support the Responses API, or does not support Responses input token counting.Send the request to /v1/chat/completions, or choose another model.
400invalid_routeThis type of model cannot be called on /v1/inference.Use the endpoint named in the message.
400invalid_model_typeThe model sent to /v1/rerank is not a reranker.Use a reranker model.
400invalid_queryquery is missing or empty on /v1/rerank.Send a non-empty query string.
400invalid_documentsdocuments is not a non-empty list of strings on /v1/rerank.Send a non-empty list of strings.
400invalid_document_entryOne document on /v1/rerank is not a non-empty string.Fix the document at the index named in the message.
400invalid_top_ntop_n is not an integer between 1 and the number of documents.Send top_n in that range, or leave it out.
400invalid_nn must be an integer from 1 to 10.Request between 1 and 10 images.
400invalid_sizesize is not "<width>x<height>" with both sides between 64 and 4096 pixels.Send a size such as "1024x1024".
400invalid_dimensionswidth and height are not integers between 64 and 4096 pixels.Send both values in that range.
400invalid_stepsThe number of inference steps is not a positive number.Send a positive number of steps, or leave it out.
400invalid_response_formatresponse_format is not "url" or "b64_json" (images and video).Send "url" or "b64_json".
400missing_promptprompt is missing on /v1/video/generations.Send a prompt.
400missing_inputinput (the text to speak) is missing on /v1/audio/speech.Send the text in input.
400voice_requiredThis speech model needs a voice.Send a voice from the model page.
400invalid_voiceThe voice is not one of this model's voices.Use one of the voices listed in the message.
400reference_audio_requiredThis voice-cloning model needs referenceAudioUrl.Send an HTTPS URL of a reference audio file.
400invalid_reference_audio_urlreferenceAudioUrl is not a valid HTTPS URL, or points to a blocked address.Send a public HTTPS URL.
400invalid_content_typeAudio transcription was not sent as multipart/form-data with a file field.Send the audio as a file field in multipart/form-data.
400model_pricing_missingNo price is configured for this model on this endpoint.Contact support with the request ID. The request was not billed.
400unsupported_pricing_unitThis model is priced in a unit this endpoint does not bill.Check that the model is served on this endpoint, or contact support.
401unauthorizedNo valid API key or session was sent to /v1/user/balance.Send your API key as Authorization: Bearer.
404user_not_foundThe account of this API key was not found.Check the key, or contact support.
500billing_configuration_errorThe cost of the request could not be calculated for this model.Contact support with the request ID. The request was not billed.
500model_pricing_errorNo price is configured for this speech model.Contact support with the request ID. The request was not billed.
500model_configuration_errorThe request has no output limit, and this model needs one. The request is not billed.Send max_tokens (max_output_tokens on POST /v1/responses), or contact support with the request ID.
500server_configuration_errorA configuration error on our side prevented the request.Retry later, and contact support with the request ID if it persists.
500storage_errorThe generated audio file could not be saved.Retry the request.
500internal_errorVideo input files or the generated video could not be processed.Retry the request, and contact support with the request ID if it persists.
502voice_registration_failedThe reference audio could not be registered for voice cloning.Retry, or use a different audio file.

Notices

A notice tells you how a request was applied. It comes with a normal, successful response, never instead of one. The X-DEVUP-Warnings response header lists the codes of the notices that apply, comma-separated, on streamed and non-streamed responses alike; it is absent when there is none. Non-streamed responses also list each notice's message in _devup.warnings. The codes are stable; use them rather than the message text in your code.

Response Headers
HTTP/2 200
content-type: text/event-stream
x-request-id: req_3f9a1c07b2e64d58a0c9e1f4b7d2a6c3
x-devup-warnings: parameter_not_supported,continue_turn_added
CodeWhenExample messageWhat to do
parameter_not_supportedThe model does not take this parameter. The request is answered without it.This model does not take the 'top_p' parameter; the request was answered without it.Leave the parameter out to remove the notice.
parameter_supersededBoth max_tokens and max_completion_tokens were sent. max_completion_tokens applies.Both 'max_tokens' and 'max_completion_tokens' were sent; 'max_completion_tokens' applies.Send only max_completion_tokens.
responses_parameter_not_supportedThe parameter is not part of the Responses API. The request is answered without it.The Responses API does not take the 'top_k' parameter; the request was answered without it.Leave the parameter out to remove the notice.
reasoning_applied_as_effortreasoning: {"enabled": true} was sent to a model that takes reasoning_effort. It is applied as reasoning_effort "medium".Parameter 'reasoning' was applied as reasoning_effort "medium".Send reasoning_effort to choose another level.
reasoning_supersededBoth reasoning and reasoning_effort were sent to a model that takes reasoning_effort. reasoning_effort applies.Both 'reasoning' and 'reasoning_effort' were sent; 'reasoning_effort' applies.Send only reasoning_effort.
reasoning_disable_not_appliedreasoning: {"enabled": false} was sent to a model that takes reasoning_effort. The model reasons at its default level.This model reasons at its default level; 'reasoning' with enabled false does not turn it off. Use 'reasoning_effort' to set its reasoning.Send reasoning_effort to set the model's reasoning.
tool_choice_not_enforcedtool_choice is "required" or a named function, on a model that decides for itself whether to call a tool. The request is sent as is; the model may answer with text instead of a tool call.This model selects tools on its own; 'tool_choice' values other than "auto" and "none" are not enforced.Check whether the reply has tool_calls, or choose a model that enforces tool_choice: tool_choice on /v1/models shows each model's values.
reasoning_not_availablereasoning_effort or reasoning was sent to a model that has no configurable reasoning mode. The model answers directly.This model does not offer a configurable reasoning mode; the request was answered without it.Leave the parameter out, or choose a model that reasons: reasoning.mode on /v1/models shows each model's mode.
json_fence_removedresponse_format is json_object or json_schema, on a model that can return JSON inside a Markdown code fence (```json ... ```). A fence around the whole reply is removed, with or without streaming, so the content parses as JSON. Any other reply is returned unchanged. When streaming, a reply that opens with a fence and reaches max_tokens before the fence closes arrives without its opening marker, since the start of the stream is already sent.This model can return JSON inside a Markdown code fence; a fence around the whole reply is removed, so the content is the JSON itself.None needed. Parse message.content as JSON. A reply that reaches max_tokens is incomplete JSON in any case: raise max_tokens.
structured_output_via_toolresponse_format is json_schema, without streaming and without tools, on a model that does not apply json_schema itself but enforces a named tool_choice. The schema is sent as one forced tool, and the tool call's arguments are returned as message.content, with finish_reason "stop". The reply is checked against the schema; a reply that does not match is tried once more, at no cost to you.This model produces structured output through a tool call; the result is returned as the message content, in the requested json_schema.None needed. Parse message.content as JSON.
structured_output_not_matchedIn the case above, the reply still does not match the schema after the second try, and the request did not set strict: true. The JSON is returned as the model produced it.This model's JSON does not match every rule of the requested json_schema; it is returned as produced. Send strict: true to receive an error instead.Validate message.content against your schema, or send strict: true to receive the error structured_output_mismatch instead.
continue_turn_addedThe conversation ends with an assistant message, and the model answers only after a user message. A user message "Continue." is added, and the model answers with a new message.The conversation ends with an assistant message. A user message "Continue." was added so that the model answers with a new message.None needed. To choose the text of that message, end the conversation with your own user message.
max_tokens_capped_by_balanceA request without tools (no tools array, or an empty one), when the balance does not cover a reply of the requested length on this model (max_tokens, or the model's default output length, at most its max_output_tokens, when max_tokens is absent) for every requested choice (n). The request is answered with max_tokens set to the largest number of output tokens the balance covers, and the message gives that number. A request with a non-empty tools array is not shortened: it returns HTTP 402 insufficient_balance instead.max_tokens was set to 2,827: your balance covers 2,827 output tokens on this model.Top up the balance to receive longer replies, or send a smaller max_tokens to remove the notice.
max_tokens_capped_by_budgetA request with a finite-budget Scoped JWT, without tools and without an explicit output token limit (max_tokens, max_completion_tokens, or max_output_tokens), when the token's remaining DZD allowance covers part of the model's default output length. Answered with the output limit set to the largest number of output tokens the remaining token budget covers, and the message gives that number. A request with an explicit output limit above the remaining budget or a non-empty tools array is not shortened: it returns HTTP 402 budget_exhausted instead.max_tokens was set to 1,024: the remaining token budget covers 1,024 output tokens on this model.Issue a Scoped JWT with a larger budget to receive longer replies, or send an explicit output limit within the remaining budget to remove the notice.

Quick Reference

StatusCodeRetryableAction
400invalid_request_bodyNoFix the request payload.
400missing_modelNoSpecify a valid model identifier in the model field.
400cache_retention_unsupportedNoUse a supported ttl, check model support, or remove service_tier.
400use_responses_apiNoSend the request to /v1/responses, or remove tools if the model supports chat without them.
400unsupported_contentNoRemove unsupported content (audio, image, video) or use a multimodal model.
400unsupported_parameterNoRemove the unsupported parameter or check model documentation.
400invalid_max_tokensNoSend a value between 1 and the model's max_output_tokens from GET /v1/models.
400context_length_exceededNoShorten input tokens or switch to a model with a larger context window.
400invalid_request_formatNoCheck the field path indicated in the error message and correct payload format.
400scoped_budget_unbounded_requestNoUse inline data: images or a bounded model with a Scoped JWT, or send an sk-devup-... account API key.
401invalid_api_keyNoRegenerate or correct your API key.
401missing_api_keyNoInclude Authorization: Bearer sk-devup-... header (or x-api-key on GET /v1/models, GET /v1/models/{model}, GET /v1/me and GET /v1/me/avatar).
401token_expiredNoGenerate a new scoped token or refresh before expiry.
401token_revokedNoGenerate a new scoped token from Dashboard → API Keys.
402insufficient_balanceNoTop up master account DZD balance at Dashboard → Billing.
402budget_exhaustedNoIssue a new scoped token in Dashboard → API Keys (topping up balance does not reset token spend).
403account_suspendedNoContact DEVUP AI support.
403model_not_allowedNoRequest an allowed model or issue a new scoped token covering that model.
403scoped_token_not_allowedNoGET /v1/me and GET /v1/me/avatar accept account API keys only. Send an sk-devup- key.
404model_not_foundNoVerify model identifier against model catalog (GET /v1/models).
404avatar_not_foundNoThe account has no profile picture. Show the initial from GET /v1/me instead.
404endpoint_not_foundNoCheck the method and path against the API reference.
409request_outcome_pendingNoDo not repeat automatically; retain x-request-id and confirm the outcome first.
429rate_limit_exceededYesYour account's rate limit is reached. Wait for Retry-After, then retry.
429model_at_capacityYesThe model is at capacity. Wait for Retry-After (5s), then retry; the OpenAI and Anthropic SDKs retry it automatically.
429concurrency_limit_exceededYesToo many requests in progress for your account. Wait for in-flight requests to finish, then retry.
429tpm_limit_exceededYesYour account's tokens-per-minute limit is reached. Retry after the Retry-After interval.
429flex_capacity_unavailableYesWait 60s or omit service_tier to use standard tier.
500server_errorYesRetry with backoff; if the error persists, contact support with the request ID.
502DEVUP_COMPUTE_ERRORYesThe request was not billed; retry with exponential backoff.
503model_unavailableYesModel temporarily unavailable; honor Retry-After and/or retry-after-ms when present.
503service_unavailableYesWait for Retry-After (5s); retry with backoff.