Error Handling
The Yunxin error model — response shape, status codes, error codes, and retry guidance.
Error response format
When a request fails, Yunxin returns a non-2xx HTTP status and a consistent JSON envelope. The
error.code field is the stable, machine-readable identifier you should branch on:
{
"error": {
"code": "model_not_found",
"message": "No model matches the requested id.",
"request_id": "req_8f3c2a1b",
"details": { "model": "does-not-exist" },
"docs_url": "https://api.yuhuanstudio.com/docs/errors"
},
"timestamp": 1709251200,
"correlation_id": "c0a8...e91"
}| Field | Description |
|---|---|
error.code | Stable, machine-readable error code. Branch on this. |
error.message | Human-readable description. Do not parse it. |
error.request_id | Identifier for this request — include it in support requests. Also returned as the X-Request-ID response header. |
error.details | Optional structured context (e.g. offending field, required balance). |
error.docs_url | Optional link to relevant documentation. |
timestamp | Unix timestamp (seconds) when the error was generated. |
correlation_id | Trace identifier spanning the request across services. |
Validation failures (HTTP 422) group the offending fields under error.details.fields, mapping each
field path to its specific message.
HTTP status codes
| Status | Typical code(s) | Meaning |
|---|---|---|
| 400 | bad_request | Malformed request or missing required fields. |
| 401 | authentication_error, invalid_api_key | Missing or invalid API key. |
| 402 | insufficient_balance | Not enough credit balance to serve the request. |
| 403 | authorization_error, model_tier_restricted, account_suspended | Not permitted. |
| 404 | not_found, model_not_found, file_not_found | Resource does not exist. |
| 409 | conflict | The request conflicts with current state. |
| 413 | payload_too_large | Request body exceeds size limits. |
| 422 | validation_error | Parameters failed validation (see details.fields). |
| 429 | rate_limit_exceeded, quota_exceeded | Throttled — see Rate Limits. |
| 500 | internal_error | Unexpected server-side error. |
| 502 | provider_error | The upstream provider returned an error. |
| 503 | provider_unavailable, service_unavailable | Temporarily unavailable. |
| 504 | provider_timeout, gateway_timeout | Upstream did not respond in time. |
Common error codes
Authentication & authorization
| Code | Solution |
|---|---|
authentication_error | Send a valid key via Authorization: Bearer sk-... or X-API-Key. |
invalid_api_key | The key is wrong, expired, or revoked — generate a new one in the Dashboard. |
authorization_error | The key/account lacks access to this resource. |
model_tier_restricted | The model requires a higher subscription tier — upgrade to use it. |
Request & model
| Code | Solution |
|---|---|
model_not_found | Check the model id against GET /v1/models. |
validation_error | Inspect details.fields and fix the offending parameters. |
payload_too_large | Reduce the request size, or upload large inputs via the File API. |
insufficient_balance | Top up your credit balance in the Dashboard. |
quota_exceeded | You hit a usage quota — wait for the reset or raise your limit. |
Provider & availability
| Code | Solution |
|---|---|
provider_error | The upstream provider failed. Inspect details; retry or try another model. |
provider_timeout | Retry with backoff, a shorter prompt, or a different model. |
provider_unavailable | The provider is down. Fallback may have been attempted (see X-Fallback-* headers); retry later. |
Retrying safely
These errors are generally retryable with exponential backoff and jitter:
rate_limit_exceeded, provider_error, provider_timeout, provider_unavailable.
For 429, prefer the Retry-After header (and error.retry_after) when present instead of guessing.
Do not blindly retry 4xx validation/auth errors — fix the request first.
import os, time, random
from openai import OpenAI, APIError, RateLimitError
client = OpenAI(
api_key=os.environ["YUNXIN_API_KEY"],
base_url="https://api.yuhuanstudio.com/v1",
)
def with_retry(fn, max_retries=5):
for attempt in range(max_retries):
try:
return fn()
except RateLimitError as e:
retry_after = getattr(e, "retry_after", None)
wait = retry_after if retry_after else (2 ** attempt) + random.uniform(0, 1)
time.sleep(wait)
except APIError as e:
# Retry only transient upstream failures (502/503/504); re-raise the rest.
if e.status_code in (502, 503, 504):
time.sleep((2 ** attempt) + random.uniform(0, 1))
else:
raise
raise RuntimeError("Max retries exceeded")
resp = with_retry(lambda: client.chat.completions.create(
model="model-id",
messages=[{"role": "user", "content": "Hello"}],
))Always log request_id (or the X-Request-ID header) alongside failures. It's the fastest way for
support to trace exactly what happened.
How is this guide?