API error codes

Every failure this gateway returns, measured against the live endpoint on 2026-09-01. Of the 8 failures it returns, 5 do not mean what their status code implies, and 2 of those get retried by the official SDKs before your program ever sees them.

Verified 2026-09-01

Status code misleads

Read error.code, not the status code

A wrong model name comes back as 503. A missing messages field comes back as 500. Both are permanent mistakes in your request — no amount of retrying fixes either — but openai-python, openai-node and the Anthropic SDKs all retry 408, 409, 429 and every 5xx twice by default, with exponential backoff. So one typo becomes three round trips and tens of seconds of waiting before the real reason surfaces. The body always carries the real reason in error.code; the status code is the part that lies.

Reference

Status codes

Ordered by how often people actually hit them, not by number.

  • HTTP 401empty string
    What actually happened
    The key does not exist, was revoked, or the Authorization header is missing altogether.
    What to do
    Confirm the key still exists on the API Keys page in the console, or create a new one. One thing this is not: a missing "Bearer " prefix — the gateway accepts the bare key too, so that is never the cause.
    SDK retries it
    No — fails immediately
    Measured on the live endpoint
    probes-errors.mjs: invalid-token / missing-auth
    Message returned
    Invalid token
  • HTTP 503model_not_foundStatus code misleads
    What actually happened
    The model ID is not in this catalog — almost always copied from another provider’s docs (gpt-4o, claude-sonnet-4-5). Nothing is down; there is simply no route for a model that does not exist here.
    What to do
    Check the ID against GET /v1/models, which is the authoritative list. Every ID here is vendor/model, for example deepseek/deepseek-v4-flash.
    SDK retries it
    Yes — twice by default
    Measured on the live endpoint
    probes-errors.mjs: unknown-model
    Message returned
    No available channel for model gpt-4o under group y-api (distributor)
  • HTTP 403insufficient_user_quotaStatus code misleads
    What actually happened
    The account balance reached zero. The message is in Chinese and quotes the remaining balance with a fullwidth $, which is why searching for the English text finds nothing.
    What to do
    Top up at https://y-api.bestvirtualgoods.com/app/billing. Credit is restored immediately, existing keys keep working, and no code changes.
    SDK retries it
    No — fails immediately
    Confirmed in upstream source, not triggered here
    service/billing_session.go:355-359
    Message returned
    用户额度不足, 剩余额度: $0.00
  • HTTP 403pre_consume_token_quota_failedStatus code misleads
    What actually happened
    The account still has credit, but this one key hit the per-key cap set when it was created. The message quotes both the key’s remaining quota and the amount this request needed.
    What to do
    Raise or remove that key’s limit on the API Keys page, or switch to a key without a cap. Topping up the account does not help — the cap is per key.
    SDK retries it
    No — fails immediately
    Measured on the live endpoint
    probes-errors.mjs: quota-exhausted
    Message returned
    token quota is not enough, token remain quota: $0.000002, need quota: $0.000074
  • HTTP 500invalid_requestStatus code misleads
    What actually happened
    A required field is absent from the request body, usually messages. This is a malformed-request error reported as a server error.
    What to do
    The message names the field verbatim, so read it rather than the status code. Fix the body; retrying is guaranteed to fail again.
    SDK retries it
    Yes — twice by default
    Measured on the live endpoint
    probes-errors.mjs: missing-field
    Message returned
    field messages is required
  • HTTP 400invalid_request_errorStatus code misleads
    What actually happened
    The endpoint does not exist here — /v1/embeddings, /v1/completions and /v1/images/generations all land in this case. The body then claims messages is required, which points at something entirely unrelated to the real problem.
    What to do
    This gateway serves chat completions and the Anthropic messages endpoint. If a framework calls an embeddings endpoint under the hood, that part needs a different provider.
    SDK retries it
    No — fails immediately
    Measured on the live endpoint
    probes-errors.mjs: unsupported-endpoint
    Message returned
    `messages` is required and must be a non-empty array.
  • HTTP 400empty string
    What actually happened
    The request body is not valid JSON. The upstream doubles its own "Invalid request:" prefix, which is cosmetic.
    What to do
    Usually a hand-built payload or shell quoting. Validate the JSON before sending; in a shell, keep the body in single quotes.
    SDK retries it
    No — fails immediately
    Measured on the live endpoint
    probes-errors.mjs: malformed-json
    Message returned
    Invalid request: Invalid request: invalid JSON request body
  • HTTP 404empty string
    What actually happened
    POST /v1/messages/count_tokens is not implemented. Claude Code and the Anthropic SDK call it to estimate context size before sending a request.
    What to do
    Nothing to fix on your side. Clients either skip the estimate or show a warning; chat, streaming and tool use are unaffected.
    SDK retries it
    No — fails immediately
    Measured on the live endpoint
    probes-errors.mjs: count-tokens
    Message returned
    Invalid URL (POST /v1/messages/count_tokens)

Silent failures

Worse than an error: HTTP 200

Three failures return 200, raise no exception, and let your program carry on. What is wrong is the content or the bill — which is exactly why they are hard to find on your own.

Images are accepted, then ignored

Five models carry an image_ratio flag upstream. That flag is a billing coefficient, not a vision capability. All five accept a data-URL image, return 200, and answer confidently about a picture they never saw — probed with a solid green PNG, none of them named the colour. The recommended model rejects images with a 400 instead, which is the safer of the two failures.

From the client compatibility matrix

max_completion_tokens caps the text, not the bill

Capped at 12 tokens, moonshotai/kimi-k2.5 billed 261 — 21.8× the cap. Truncation itself works (finish_reason=length); the overage is reasoning tokens, which are billed but never appear in content. Any cost estimate derived from the cap will be low by that factor.

From the client compatibility matrix

Anthropic message ids have no msg_ prefix

POST /v1/messages returns a bare hex id. Code that asserts on the msg_ prefix, or parses the id to route a response, will not match — even though the rest of the payload is compliant.

From the client compatibility matrix

Parsing

What an error body looks like

The wrapper is always {"error": {...}}, but the field set is not stable: some errors carry param, others omit it, and code is frequently an empty string. Parse defensively — treat every field as optional.

401, no param field
{"error":{"code":"","message":"Invalid token (request id: 2026090114474514374…)","type":"new_api_error"}}
404, param present but empty
{"error":{"message":"Invalid URL (POST /v1/messages/count_tokens)","type":"invalid_request_error","param":"","code":""}}

Every message ends with a request id, and it differs on every call. Strip it before comparing messages against this page — and include it when you report a problem, because it is what identifies your exact request in the logs.

Triage

Three steps that isolate almost anything

In order. Each one rules out a layer, so the answer is wherever the sequence stops.

  1. Check the key and the route first

    GET /v1/models costs nothing and uses the same key. A 200 with a model list proves the key, the network and the CDN edge are all fine — which means the problem is in your request body, not your credentials.

    curl -s https://api.y-api.bestvirtualgoods.com/v1/models -H "Authorization: Bearer $YAPI_KEY" | head -c 200
  2. Reproduce it with curl

    This takes the SDK out of the picture. If curl succeeds where your code fails, the difference is in how the library builds the request — not in the gateway.

    curl -i https://api.y-api.bestvirtualgoods.com/v1/chat/completions \
      -H "Authorization: Bearer $YAPI_KEY" \
      -H "Content-Type: application/json" \
      -d '{"model":"deepseek/deepseek-v4-flash","messages":[{"role":"user","content":"hi"}]}'
  3. Turn retries off while debugging

    With retries disabled, a 500 or 503 caused by your own request shows up on the first attempt instead of after two pointless ones. Put it back afterwards — retries are worth having against real transient failures.

    client = OpenAI(
        base_url="https://api.y-api.bestvirtualgoods.com/v1",
        api_key=os.environ["YAPI_KEY"],
        max_retries=0,  # debugging only
    )

Not one of these?

The status page shows whether the gateway itself is degraded, with the last 90 days of checks. If it is green and you are still stuck, the request id from the error body is the one thing worth sending us.