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.
{
"error": {
"message": "Human-readable description of the error.",
"type": "devup_error",
"code": "machine_readable_error_code"
}
}| Field | Type | Description |
|---|---|---|
| error.message | string | Human-readable explanation of the error. Safe to display to end users. |
| error.type | string | Always "devup_error". |
| error.code | string | Machine-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.
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum number of requests allowed in the current window. |
| X-RateLimit-Remaining | Number of requests remaining in the current window. |
| X-RateLimit-Reset | Unix timestamp (ms) when the current window resets. |
| Retry-After | Seconds to wait before retrying the request. |
| retry-after-ms | Milliseconds 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.
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-warningsBoth 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.
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.
{
"error": {
"message": "The \"model\" field is required. Example: \"deepseek-ai/DeepSeek-V4-Pro\"",
"type": "devup_error",
"code": "missing_model"
}
}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.
{
"error": {
"message": "Prompt cache retention with ttl \"1h\" is not available for this model.",
"type": "devup_error",
"code": "cache_retention_unsupported"
}
}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.
{
"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"
}
}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.
{
"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"
}
}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.
{
"error": {
"message": "This model does not accept audio input.",
"type": "devup_error",
"code": "unsupported_content"
}
}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.
{
"error": {
"message": "A parameter in the request is not supported by this model: seed.",
"type": "devup_error",
"code": "unsupported_parameter"
}
}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.
{
"error": {
"message": "The request is longer than this model's context window.",
"type": "devup_error",
"code": "context_length_exceeded"
}
}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.
{
"error": {
"message": "The request does not match the format this model expects. Check messages[0].content.",
"type": "devup_error",
"code": "invalid_request_format"
}
}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.
{
"error": {
"message": "This model does not support tool calling. Remove tools and tool_choice from the request.",
"type": "devup_error",
"code": "tools_not_supported"
}
}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.
{
"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"
}
}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.
{
"error": {
"message": "This model needs the conversation to end with a user message.",
"type": "devup_error",
"code": "conversation_must_end_with_user"
}
}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.
{
"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"
}
}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.
{
"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"
}
}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.
{
"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"
}
}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.
{
"error": {
"message": "The model rejected the request. Check the messages and parameters against the API reference.",
"type": "devup_error",
"code": "invalid_request_error"
}
}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-...).
{
"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"
}
}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.
{
"error": {
"message": "The API key provided is invalid or has been deactivated.",
"type": "devup_error",
"code": "invalid_api_key"
}
}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.
{
"error": {
"message": "Provide your API key as: Authorization: Bearer sk-devup-...",
"type": "devup_error",
"code": "missing_api_key"
}
}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.
{
"error": {
"message": "This scoped token expired at 2026-08-14T10:00:00.000Z.",
"type": "devup_error",
"code": "token_expired"
}
}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.
{
"error": {
"message": "This scoped token has been revoked.",
"type": "devup_error",
"code": "token_revoked"
}
}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).
{
"error": {
"message": "Your balance is insufficient for this request. Top up at https://devupai.com/dashboard/billing.",
"type": "devup_error",
"code": "insufficient_balance"
}
}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.
{
"error": {
"message": "Budget exhausted: 50.00 / 50.00 DZD spent.",
"type": "devup_error",
"code": "budget_exhausted"
}
}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.
{
"error": {
"message": "Account suspended. Contact support.",
"type": "devup_error",
"code": "account_suspended"
}
}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.
{
"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"
}
}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.
{
"error": {
"message": "The requested model was not found.",
"type": "devup_error",
"code": "model_not_found"
}
}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.
{
"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"
}
}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.
{
"error": {
"message": "Rate limit exceeded. Please slow down your requests and try again shortly.",
"type": "devup_error",
"code": "rate_limit_exceeded"
}
}Response Headers
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1790000000000
Retry-After: 12Too 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.
{
"error": {
"message": "This model is currently at capacity. Retry in a few seconds.",
"type": "devup_error",
"code": "model_at_capacity"
}
}Response Headers
Retry-After: 5
retry-after-ms: 5000Too 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.
{
"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
Retry-After: 2
X-Concurrency-Limit: 50Too 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.
{
"error": {
"message": "Token-per-minute limit reached for this account. Retry after the indicated delay.",
"type": "devup_error",
"code": "tpm_limit_exceeded"
}
}Response Headers
Retry-After: 12
X-TPM-Limit: 500000Server 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.
{
"error": {
"message": "The model could not complete this request. Retry it; retrying usually succeeds.",
"type": "devup_error",
"code": "server_error"
}
}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.
{
"error": {
"message": "The model returned an empty response. The request was not billed. Retrying usually succeeds.",
"type": "devup_error",
"code": "DEVUP_COMPUTE_ERROR"
}
}More Error Codes
Validation and endpoint-specific errors. None of them is fixed by retrying the same request, except where the action says so.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 405 | admin_operation_requires_post | This operation requires POST. | Send a POST request. |
| 403 | admin_origin_required | Submit this operation from the application. | Open the application and submit the request again. |
| 400 | admin_confirmation_required | Confirmation is required for this operation. | Confirm the intended operation. |
| Action result | recovery_authorization_required | Verify a recovery code before updating your password. | Verify a new recovery code. |
| Action result | password_recovery_unavailable | Password recovery could not be completed. | Verify a new recovery code and try again. |
| Action result or notice | password_recovery_review_required | Password recovery requires a review before continuing. | Contact support before trying again. |
| Action notice | session_revocation_required | The password is updated; other sessions may remain active. | Contact support for a session review. |
| Action result | payment_receipt_not_found | No completed payment receipt matches the reference in your account. | Select a completed payment from your billing history. |
| Action result | receipt_email_unavailable | Receipt sending is temporarily unavailable. | Try again shortly. |
| 404 | network_volume_not_found | The selected network volume is not available in your account. | Select a volume from your account. |
| 400 | missing_tools | tool_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". |
| 400 | invalid_max_tokens | max_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. |
| 404 | endpoint_not_found | No 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. |
| 404 | avatar_not_found | The 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. |
| 403 | scoped_token_not_allowed | GET /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. |
| 400 | payload_too_large | messages has more than 512 entries, or an embeddings input has more than 2,048 entries. | Send fewer entries per request. |
| 400 | invalid_value | A parameter has a value the model does not accept. | Check the parameter's allowed values in the API reference. |
| 400 | missing_required_parameter | A parameter the model requires is missing. | Add the parameter named in the message. |
| 400 | permission_denied | The request was blocked by the safety system. | Change the content of the request. |
| 400 or 429 | insufficient_quota | The request could not be served because a usage quota was reached. | Retry later. If it persists, contact support with the request ID. |
| 400 | unsupported_destination | The 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. |
| 400 | invalid_route | This type of model cannot be called on /v1/inference. | Use the endpoint named in the message. |
| 400 | invalid_model_type | The model sent to /v1/rerank is not a reranker. | Use a reranker model. |
| 400 | invalid_query | query is missing or empty on /v1/rerank. | Send a non-empty query string. |
| 400 | invalid_documents | documents is not a non-empty list of strings on /v1/rerank. | Send a non-empty list of strings. |
| 400 | invalid_document_entry | One document on /v1/rerank is not a non-empty string. | Fix the document at the index named in the message. |
| 400 | invalid_top_n | top_n is not an integer between 1 and the number of documents. | Send top_n in that range, or leave it out. |
| 400 | invalid_n | n must be an integer from 1 to 10. | Request between 1 and 10 images. |
| 400 | invalid_size | size is not "<width>x<height>" with both sides between 64 and 4096 pixels. | Send a size such as "1024x1024". |
| 400 | invalid_dimensions | width and height are not integers between 64 and 4096 pixels. | Send both values in that range. |
| 400 | invalid_steps | The number of inference steps is not a positive number. | Send a positive number of steps, or leave it out. |
| 400 | invalid_response_format | response_format is not "url" or "b64_json" (images and video). | Send "url" or "b64_json". |
| 400 | missing_prompt | prompt is missing on /v1/video/generations. | Send a prompt. |
| 400 | missing_input | input (the text to speak) is missing on /v1/audio/speech. | Send the text in input. |
| 400 | voice_required | This speech model needs a voice. | Send a voice from the model page. |
| 400 | invalid_voice | The voice is not one of this model's voices. | Use one of the voices listed in the message. |
| 400 | reference_audio_required | This voice-cloning model needs referenceAudioUrl. | Send an HTTPS URL of a reference audio file. |
| 400 | invalid_reference_audio_url | referenceAudioUrl is not a valid HTTPS URL, or points to a blocked address. | Send a public HTTPS URL. |
| 400 | invalid_content_type | Audio transcription was not sent as multipart/form-data with a file field. | Send the audio as a file field in multipart/form-data. |
| 400 | model_pricing_missing | No price is configured for this model on this endpoint. | Contact support with the request ID. The request was not billed. |
| 400 | unsupported_pricing_unit | This model is priced in a unit this endpoint does not bill. | Check that the model is served on this endpoint, or contact support. |
| 401 | unauthorized | No valid API key or session was sent to /v1/user/balance. | Send your API key as Authorization: Bearer. |
| 404 | user_not_found | The account of this API key was not found. | Check the key, or contact support. |
| 500 | billing_configuration_error | The cost of the request could not be calculated for this model. | Contact support with the request ID. The request was not billed. |
| 500 | model_pricing_error | No price is configured for this speech model. | Contact support with the request ID. The request was not billed. |
| 500 | model_configuration_error | The 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. |
| 500 | server_configuration_error | A configuration error on our side prevented the request. | Retry later, and contact support with the request ID if it persists. |
| 500 | storage_error | The generated audio file could not be saved. | Retry the request. |
| 500 | internal_error | Video input files or the generated video could not be processed. | Retry the request, and contact support with the request ID if it persists. |
| 502 | voice_registration_failed | The 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.
HTTP/2 200
content-type: text/event-stream
x-request-id: req_3f9a1c07b2e64d58a0c9e1f4b7d2a6c3
x-devup-warnings: parameter_not_supported,continue_turn_added| Code | When | Example message | What to do |
|---|---|---|---|
| parameter_not_supported | The 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_superseded | Both 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_supported | The 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_effort | reasoning: {"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_superseded | Both 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_applied | reasoning: {"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_enforced | tool_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_available | reasoning_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_removed | response_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_tool | response_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_matched | In 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_added | The 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_balance | A 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_budget | A 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
| Status | Code | Retryable | Action |
|---|---|---|---|
| 400 | invalid_request_body | No | Fix the request payload. |
| 400 | missing_model | No | Specify a valid model identifier in the model field. |
| 400 | cache_retention_unsupported | No | Use a supported ttl, check model support, or remove service_tier. |
| 400 | use_responses_api | No | Send the request to /v1/responses, or remove tools if the model supports chat without them. |
| 400 | unsupported_content | No | Remove unsupported content (audio, image, video) or use a multimodal model. |
| 400 | unsupported_parameter | No | Remove the unsupported parameter or check model documentation. |
| 400 | invalid_max_tokens | No | Send a value between 1 and the model's max_output_tokens from GET /v1/models. |
| 400 | context_length_exceeded | No | Shorten input tokens or switch to a model with a larger context window. |
| 400 | invalid_request_format | No | Check the field path indicated in the error message and correct payload format. |
| 400 | scoped_budget_unbounded_request | No | Use inline data: images or a bounded model with a Scoped JWT, or send an sk-devup-... account API key. |
| 401 | invalid_api_key | No | Regenerate or correct your API key. |
| 401 | missing_api_key | No | Include 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). |
| 401 | token_expired | No | Generate a new scoped token or refresh before expiry. |
| 401 | token_revoked | No | Generate a new scoped token from Dashboard → API Keys. |
| 402 | insufficient_balance | No | Top up master account DZD balance at Dashboard → Billing. |
| 402 | budget_exhausted | No | Issue a new scoped token in Dashboard → API Keys (topping up balance does not reset token spend). |
| 403 | account_suspended | No | Contact DEVUP AI support. |
| 403 | model_not_allowed | No | Request an allowed model or issue a new scoped token covering that model. |
| 403 | scoped_token_not_allowed | No | GET /v1/me and GET /v1/me/avatar accept account API keys only. Send an sk-devup- key. |
| 404 | model_not_found | No | Verify model identifier against model catalog (GET /v1/models). |
| 404 | avatar_not_found | No | The account has no profile picture. Show the initial from GET /v1/me instead. |
| 404 | endpoint_not_found | No | Check the method and path against the API reference. |
| 409 | request_outcome_pending | No | Do not repeat automatically; retain x-request-id and confirm the outcome first. |
| 429 | rate_limit_exceeded | Yes | Your account's rate limit is reached. Wait for Retry-After, then retry. |
| 429 | model_at_capacity | Yes | The model is at capacity. Wait for Retry-After (5s), then retry; the OpenAI and Anthropic SDKs retry it automatically. |
| 429 | concurrency_limit_exceeded | Yes | Too many requests in progress for your account. Wait for in-flight requests to finish, then retry. |
| 429 | tpm_limit_exceeded | Yes | Your account's tokens-per-minute limit is reached. Retry after the Retry-After interval. |
| 429 | flex_capacity_unavailable | Yes | Wait 60s or omit service_tier to use standard tier. |
| 500 | server_error | Yes | Retry with backoff; if the error persists, contact support with the request ID. |
| 502 | DEVUP_COMPUTE_ERROR | Yes | The request was not billed; retry with exponential backoff. |
| 503 | model_unavailable | Yes | Model temporarily unavailable; honor Retry-After and/or retry-after-ms when present. |
| 503 | service_unavailable | Yes | Wait for Retry-After (5s); retry with backoff. |