Errors
The error format, every error code Mux returns, and which errors to retry.
Errors are JSON with a single error object. code is a stable, machine-readable string; message is for humans and may change. Some errors carry extra fields.
{
"error": {
"code": "insufficient_credits",
"message": "Insufficient credits. Add credits at /v1/credits/checkout.",
"needed_usd": 0.007
}
}Branch on the HTTP status and code, not on message. In the SDKs every non-2xx response throws a MuxError with status, code and message (and the parsed body). See SDKs.
Error codes
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | invalid_request |
The body isn't valid JSON, has an unknown field, or a value is missing or out of range (for example max_results over 100, a bad date, or an amount outside 5 to 10,000). The message says which. |
Fix the request. Don't retry unchanged. |
| 400 | unknown_model |
A model id in model or models doesn't exist. |
Use an id from GET /v1/models. |
| 400 | unknown_provider |
The provider in a provider-keys path isn't exa, parallel or keenable. |
Fix the provider name. |
| 401 | invalid_api_key |
The Authorization header is missing, isn't Bearer mux-..., or the key doesn't exist or was deleted. |
Check the key. |
| 401 | key_disabled |
The key has been switched off. | Re-enable it or use another key. |
| 401 | key_expired |
The key is past its expires_at. |
Create a new key. |
| 402 | insufficient_credits |
Your balance can't cover any model that was attempted. Includes needed_usd, the price of the cheapest blocked attempt. |
Add credits. |
| 402 | key_limit_exceeded |
The request would take this API key past its credit limit. Includes needed_usd. Nothing was charged. |
Raise or reset the limit, or use another key. |
| 403 | wrong_key_type |
A management key was used to search, or an API key was used on a management endpoint. | Use the right kind of key. |
| 404 | not_found |
The key id or provider key doesn't exist in your account. | Check the id. |
| 429 | rate_limited |
This API key is sending requests faster than its rate limit. Nothing was charged. The Retry-After header says how many seconds to wait. |
Slow down, or retry after the delay. The SDKs do this for you. |
| 429 | too_many_concurrent_requests |
The account already has too many searches in flight. Nothing was charged. | Wait for some requests to finish, or lower your concurrency. |
| 502 | all_providers_failed |
Every attempted model failed or was unavailable. Includes attempts. You weren't charged. |
Retry, or add more models to models. |
| 502 | stripe_error |
Creating the Stripe Checkout session failed. | Retry shortly. |
| 503 | overloaded |
Every model you allowed is at capacity right now. Nothing was charged. Includes a Retry-After header. |
Retry shortly, or add more models to models so Mux has somewhere to fall back to. |
| 503 | byok_disabled |
Provider keys can't be stored on this deployment. | Contact support. |
| 503 | stripe_disabled |
Credit purchases aren't available. | Contact support. |
| 500 | internal |
Something went wrong on our side. | Retry with backoff. |
insufficient_credits and key_limit_exceeded
Both return 402. When you use models fallbacks, Mux skips any model it can't afford and tries the next one, so you only see a 402 when every model was blocked. If both kinds of block happened, you get key_limit_exceeded.
all_providers_failed
The attempts array shows what happened to each model, which makes this easy to debug:
{
"error": {
"code": "all_providers_failed",
"message": "All providers failed.",
"attempts": [
{ "model": "exa/auto", "source": "platform", "status": "error", "error": "exa timeout" },
{ "model": "keenable/pro", "status": "skipped", "error": "provider not configured" }
]
}
}Each failed attempt was refunded, so your balance and the key's limit are unchanged, with one exception: an attempt whose error is a provider timeout (no answer after 15 seconds) keeps the model's base price, because the provider has normally completed the search by then. Such an attempt carries a cost_usd field. See Pricing.
Rate limits
Mux limits how fast one key can search and how many searches one account can run at once, so a runaway loop can't use up shared capacity.
| Limit | Default | Error |
|---|---|---|
| Requests per second per API key | 20 sustained, bursts up to 40 | 429 rate_limited |
| Searches in flight per account | 50 | 429 too_many_concurrent_requests |
| Calls to one provider at a time | Shared across all customers | falls back to the next model, then 503 overloaded |
Successful search responses include x-ratelimit-limit (requests per second allowed) and x-ratelimit-remaining (requests left in the current burst). Rejected requests include Retry-After. Limited requests are never charged. If you need higher limits, contact us.
Responses without the error format
Requests that never reach the API handlers can get a plain response instead of the JSON error object: an unknown path returns 404, a wrong HTTP method returns 405, and a malformed query string (for example ?limit=abc) returns 400. Check the status first and parse the body only if it is JSON.
Retrying
- Don't retry 4xx errors (including
402). They won't succeed until you change the request, the key or your balance. 502 all_providers_failedis safe to retry yourself: you weren't charged. The SDKs don't retry it automatically because the gateway has already tried every model you allowed.500and other5xx(except502) and429are retried automatically by the SDKs, up to 2 retries (3 attempts in total) with exponential backoff starting at 300 ms. If the response has aRetry-Afterheader, the SDKs wait at least that long (up to 10 seconds). You can change this withmaxRetries(TypeScript) ormax_retries(Python).- Retrying a search is safe: failed attempts are refunded, and a request that errors before succeeding isn't charged.
Include the x-mux-request-id response header (or the id in the body) when contacting support about a specific request.