Skip to content
ACS Infra

Errors

Every error of the /v1 routes comes as the error object of the old platform's API, with its status codes and its code values. Code written for that API reads these errors unchanged. The openai SDK raises its usual error classes. Retry requests safely says which errors to try again.

The error object

Every error answer has the error object, and the id of the request next to it:

Error
{
  "error": {
    "message": "The model `gpt-2` does not exist. The API serves llama-8b, llama-405b, trinity-truebase.",
    "type": "invalid_request_error",
    "param": "model",
    "code": "model_not_found"
  },
  "request_id": "req_9f2c4e1a7b3d4c5e8f6a0b1c2d3e4f5a"
}
FieldWhat it is
error.messageWhat went wrong, for a person to read.
error.typeinvalid_request_error for most errors, and rate_limit_error for a rate limit. upstream_error for a failure of the model server, service_unavailable for a busy database, and internal_error when the API fails.
error.paramThe top-level request field at fault, or null.
error.codeA fixed string that a program can check, or null. Two errors can have the same status, and code tells them apart.
error.retryableWhether the same request can succeed when you send it again. It comes on a failure of the model server, and on an error that comes after the answer started.
error.retry_after_secondsWith retryable: true: how many seconds to wait first, as the Retry-After header says.
error.upstream_statusThe status that the model server answered with, when it answered.
request_idThe id of the request, the same as in its X-Request-Id header.

Every answer, an error too, has the header X-Request-Id, for example X-Request-Id: req_9f2c4e1a7b3d4c5e8f6a0b1c2d3e4f5a. The id is new for each request. An error that comes after the answer started, as the last event of a stream, has the id in request_id and in error.request_id. The API logs each request with its id, so send the id when you report a bug.

Status codes

The API answers most errors itself. The rest come from Inference, and the API names them by what Inference said.

Answers from the API

StatuscodeWhen
400invalid_requestThe request body or an id in the path is not valid, or is over a size cap. A top-level field that the API does not know gets it too. param is the top-level field, and message says where the value is and what it takes.
400bad_jsonThe request body is not JSON.
400model_not_foundThe API does not serve the model. param is model.
400chat_completions_unsupportedThe request went to POST /v1/chat/completions. Send POST /v1/completions with a prompt.
400harvest_unsupportedPOST /v1/harvest names a model that the API serves but does not harvest. param is model (Harvests on each model).
400deadline_infeasiblePOST /v1/completions without stream asks for a max_tokens above 15,600. param is max_tokens, and the answer has x-should-retry: false.
401missing_authorizationThe request has no API key (API keys).
401invalid_api_keyThe API key is wrong.
401key_revokedThe API key is revoked, also when it was revoked while its request ran.
401key_disabledThe API key is paused, also when it was paused while its request ran.
401account_suspendedYour access is suspended.
404job_not_foundNone of your Jobs has this id.
404harvest_job_not_foundNone of your harvests has this job_id.
404nullNo route has this path, or none of your Looms or Nodes has this id.
405nullThe route does not take this method. The Allow header lists the methods that it takes.
409nullThe Node is not in a state for this action. The answer has x-should-retry: false.
409harvest_not_cancellableThe harvest is done or failed, so it cannot be canceled. The answer has x-should-retry: false.
409idempotency_conflictThe Idempotency-Key came before with another request, or on another route. The answer has x-should-retry: false.
409job_cancelledThe result of a Job that you canceled.
409runningA request with the same Idempotency-Key still runs. The answer has Retry-After: 1.
409no_answerA request with the same Idempotency-Key ran, and its answer, such as a stream, cannot be sent again. The answer has x-should-retry: false.
410job_result_expiredThe result of the Job expired (Kept data). The Job stays.
413request_too_largeThe request body is larger than 8 MiB, or 50 MiB on POST /v1/harvest (Request size). The answer has x-should-retry: false.
429budget_exceededYour Budget, or the key's own Budget, cannot hold the request. The answer has x-should-retry: false.
429rate_limitedThe API key sent more requests than its rate limit allows. The type is rate_limit_error, and the answer has Retry-After.
429queue_fullThe API key has its most Completions running and waiting (Traffic). The answer has Retry-After: 5.
429job_capacityA Job cap is full, and the message names it. The answer has x-should-retry: false.
429harvest_quota_exceededThe API key started its most harvests this UTC month (Harvests). The answer has x-should-retry: false.
429harvest_concurrency_exceededYou have your most harvests pending or running on Llama 3.1 8B, or on Llama 3.1 405B and Trinity Large (Harvests). The answer has Retry-After: 30.
429harvest_capacity_exceededAll Users together have the most harvests pending or running on Llama 3.1 405B and Trinity Large (Harvests). The answer has Retry-After: 30.
429spend_capNew GPU work is paused to limit spending (Spend limit). A Completion, a Job, a Branch, or a harvest that you start gets it. The answer has Retry-After: 3600 and x-should-retry: false.
500internal_errorThe API failed, and does not know how much of the work it did. The answer has x-should-retry: false.
503db_pool_exhaustedThe API's database was busy. Nothing ran and the API held no tokens. The answer has Retry-After: 1.
503circuit_openThe API holds the model back. Inference failed its last 5 requests in a row (Inference fails), or the API has its most requests in flight to it (Traffic). Nothing ran, and you pay nothing. retryable is true, and the answer has Retry-After.

Answers about Inference

Each of these has the type upstream_error, except the two that Inference passes on as they are. A stream that has its 200 gets each of them as its last event (Inference fails during a stream).

StatuscodeWhen
400invalid_requestInference refused a value in the request. The API passes on Inference's message and param. The type is invalid_request_error.
400context_length_exceededThe prompt and max_tokens are longer than the model allows. param is prompt. The type is invalid_request_error.
400vllm_context_lengthInference failed with a 5xx status, and its message says that the prompt is too long.
400vllm_invalid_requestInference failed with a 5xx status, and its message says that the request is bad.
429rate_limitedInference has too many requests. The API passes on its Retry-After and retry-after-ms headers. The type is rate_limit_error.
502upstream_unreachableThe API could not reach Inference. retryable is true, and the answer has Retry-After: 30.
502vllm_oomInference ran out of GPU memory. retryable is true, and the answer has Retry-After: 30.
502vllm_engine_deadInference's engine stopped. retryable is true, and the answer has Retry-After: 30.
502upstream_server_errorInference failed with another status, which upstream_status gives. After a 502, 503, or 504, retryable is true and the answer has Retry-After: 30. After another status, such as 500, retryable is false and the answer has x-should-retry: false.
502upstream_authInference refused the API's own key. Your key is not the cause. The answer has x-should-retry: false.
504upstream_deadlineInference did not answer within 14 minutes. The answer has x-should-retry: false.

Not enough tokens

Before POST /v1/completions sends a request to Inference, it takes a Hold of the most tokens that the request can use. Near the end of your tokens, it lowers max_tokens to what fits (Near the end of your tokens). It answers 429 budget_exceeded only when your Budget cannot hold the prompt and one token for each choice.

A Job, a Loom Branch, and the Playground do not lower a max_tokens that you set. A Completion of theirs that your Budget cannot hold fails with budget_exceeded (Holds of background work). A harvest that your tokens cannot hold gets 429 budget_exceeded when you submit it. If your tokens run short before it starts, it fails with the harvest code insufficient_quota.

The message says how many tokens the request can use, and which Budget is short. For example, the prompt "The sky is" with "max_tokens": 2 can use 13 tokens, as the Hold counts them:

  • This request can use up to 13 tokens, more than your token budget has left. Ask for more tokens at https://v2.infra.acsresearch.org/usage/request.
  • This request can use up to 13 tokens, more than this API key's token budget has left. when the key has its own Budget.
  • When your monthly allowance is used up too, the message says so, and gives the day in UTC on which it refills.

The address opens the App's form to ask for more tokens (Ask for more tokens).

Handle the end of your Budget handles the error in code.

Unknown field

The API refuses a field that it does not know, so a misspelled field cannot change a result without a warning. An unknown field inside an object, such as a Steering vector, gets 400 invalid_request with param set to the top-level field. Its message names where the field is, for example Unknown parameter: 'apply_steering_vectors[0].scael'.

curl "$ACS_API_BASE/completions" \
  -H "Authorization: Bearer $ACS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "llama-8b", "prompt": "The sky is", "temprature": 0}'
Error
{
  "error": {
    "message": "Unknown parameter: 'temprature'.",
    "type": "invalid_request_error",
    "param": "temprature",
    "code": "invalid_request"
  },
  "request_id": "req_9f2c4e1a7b3d4c5e8f6a0b1c2d3e4f5a"
}

Unknown model

The API answers a model that it does not serve itself, from its list of served models, before it holds any tokens. A Job or a Loom Branch with such a model gets 400 model_not_found too, and the API makes nothing.

curl "$ACS_API_BASE/completions" \
  -H "Authorization: Bearer $ACS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-2", "prompt": "The sky is"}'
Error
{
  "error": {
    "message": "The model `gpt-2` does not exist. The API serves llama-8b, llama-405b, trinity-truebase.",
    "type": "invalid_request_error",
    "param": "model",
    "code": "model_not_found"
  },
  "request_id": "req_9f2c4e1a7b3d4c5e8f6a0b1c2d3e4f5a"
}

Prompt too long

The prompt and max_tokens together must fit the model's capabilities.max_model_len from GET /v1/models. In a request of several prompts, each prompt must fit with max_tokens on its own. trinity-truebase has a max_model_len of 8,192 tokens. The prompt "The sky is" has 4 tokens with the BOS token, so "max_tokens": 8190 does not fit:

curl "$ACS_API_BASE/completions" \
  -H "Authorization: Bearer $ACS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "trinity-truebase", "prompt": "The sky is", "max_tokens": 8190}'

The API refuses the request before it holds any tokens, and answers 400 with param set to prompt. In a request of several prompts, the message names the prompt that does not fit, such as prompt[1]:

Error
{
  "error": {
    "message": "This model's maximum context length is 8192 tokens, and the prompt has 4 tokens and max_tokens is 8190: 8194 in all. Shorten the prompt or lower max_tokens.",
    "type": "invalid_request_error",
    "param": "prompt",
    "code": "context_length_exceeded"
  },
  "request_id": "req_9f2c4e1a7b3d4c5e8f6a0b1c2d3e4f5a"
}

The API counts a prompt's tokens as the Hold counts them. It sends a text that is too long for its tokenizer to read on to Inference. Inference refuses such a text with the same code, in vLLM's words.

Inference fails

When Inference fails, the API answers with the type upstream_error, a code that names the failure, and retryable, as Answers about Inference lists. The API does not try a failed request again.

StatuscodeMessageWhen
502upstream_unreachableCould not reach Inference: Connection error.The API could not reach Inference.
504upstream_deadlineCould not reach Inference: Request timed out.Inference did not answer within 14 minutes. The answer has x-should-retry: false.
502upstream_server_errorInference's answer does not fit the request: and what is wrongInference's answer did not finish each choice, or its activations are missing or have another shape than the request asked for. The answer has x-should-retry: false.

After Inference fails 5 requests to a model in a row, the API sends that model no request for 60 seconds. Each request to the model in that time gets 503 circuit_open at once, and its Retry-After header and retry_after_seconds give the seconds left. Then the next requests try the model again. One that succeeds ends the pause, and one that fails starts it again. A Job's request, a Run, or a Branch of that model fails at once with the same message. Other models are not affected.

A Completion without a stream that runs for more than 150 seconds already has its 200 status. A failure after that comes as the body, in the error object. The openai SDK raises no exception for it, and returns a Completion whose error field holds the error object. Requests without a stream explains the wait.

Inference fails during a stream

A stream has its 200 status when Inference starts its answer. If Inference has not answered after 2 seconds, as while a cold model starts, the stream gets its 200 then (Requests with a stream). Each later error, such as an answer about Inference, is the last event before [DONE]:

data: {"error":{"message":"<Inference's message>","type":"upstream_error","param":null,"code":"upstream_server_error","retryable":false,"request_id":"req_9f2c4e1a7b3d4c5e8f6a0b1c2d3e4f5a"},"request_id":"req_9f2c4e1a7b3d4c5e8f6a0b1c2d3e4f5a"}

data: [DONE]

The openai SDK raises openai.APIError at the error event, after the chunks that came before it. The tokens before the error are real, and your Hold settles to the tokens that Inference used.

A stream from Inference is complete only with its last event. If it ends before that, for example when a connection closes, the API sends an error event before [DONE]. Its message is Inference ended the stream before it was complete., its code is upstream_server_error, and retryable is false. A new try runs the whole request again and pays again for each token that it streams. A cut stream therefore never looks complete. A Loom Node fails in the same way, and keeps its text so far.

Failed harvests

A harvest that fails after you submit it answers no error status. GET /v1/harvest/{job_id} answers the Job with status failed, and its error is a message that says why. Handle a failed harvest lists each cause and what to do.

A Job whose request fails answers its error at GET /v1/completion-jobs/{job_id}/result, with the status that POST /v1/completions would have answered (Fetch the result). Its request_id is the Job's request_id, not the X-Request-Id of that answer.

Errors in the openai SDK

The openai SDK raises the error class that matches the status:

StatusError class
400openai.BadRequestError
401openai.AuthenticationError
403openai.PermissionDeniedError
404openai.NotFoundError
409openai.ConflictError
429openai.RateLimitError
5xxopenai.InternalServerError
405, 410, and 413openai.APIStatusError
An error event in a streamopenai.APIError
The connection failed, or timed out before an answeropenai.APIConnectionError, or openai.APITimeoutError

Each error class of a status is a kind of openai.APIStatusError. Its status_code is the status, body holds the error object, and code, param, and type are the fields of the error object. Its request_id is the X-Request-Id header.

import os

import openai
from openai import OpenAI

client = OpenAI(base_url=os.environ["ACS_API_BASE"], api_key=os.environ["ACS_API_KEY"])
try:
    client.completions.create(model="gpt-2", prompt="The sky is")
except openai.BadRequestError as error:
    print(error.status_code, error.code, error.param)
Output
400 model_not_found model

The SDK sends some requests again before it raises the error (Retries in the openai SDK).

On this page