Errors
Error response format and common error codes
Error Response Format
When an API request fails, OpenModel returns a JSON error response with the following structure:
Web API Errors
All /web/v1 endpoints return errors in OpenModel's standard format:
{
"success": false,
"data": null,
"error": {
"code": "UNAUTHORIZED",
"msg": "API key is invalid or has been revoked",
"detail": "optional additional detail"
}
}| Field | Type | Description |
|---|---|---|
success | boolean | Always false for error responses. |
data | null | Always null for error responses. |
error.code | string | A string error code for programmatic error handling (e.g., "BAD_REQUEST", "UNAUTHORIZED"). |
error.msg | string | A human-readable error message describing what went wrong. |
error.detail | string | Optional additional detail (e.g., validation error specifics). Omitted when empty. |
Proxy API Errors
Proxy endpoints (/v1/responses, /v1/messages, /v1beta/models/*) return errors in the format matching the requested API, so that SDK error handling works as expected.
OpenAI format (/v1/responses):
{
"error": {
"message": "Invalid API key provided",
"type": "invalid_request_error",
"code": "invalid_api_key"
}
}Anthropic format (/v1/messages):
{
"type": "error",
"error": {
"type": "authentication_error",
"message": "Invalid API key provided"
}
}Gemini format (/v1beta/models/*):
{
"error": {
"code": 401,
"message": "Invalid API key provided",
"status": "UNAUTHENTICATED"
}
}Error Codes
Error codes are string identifiers used in the error.code field of Web API responses.
Common Errors
| Code | HTTP Status | Description |
|---|---|---|
BAD_REQUEST | 400 | The request body is malformed or missing required fields. |
UNAUTHORIZED | 401 | Authentication failed — invalid or missing credentials. |
FORBIDDEN | 403 | Permission denied — insufficient access rights. |
NOT_FOUND | 404 | The requested endpoint does not exist. |
METHOD_NOT_ALLOWED | 405 | The HTTP method is not supported for this endpoint. |
CONFLICT | 409 | A conflict occurred (e.g., concurrent modification). |
TOO_MANY_REQUESTS | 429 | Rate limit exceeded. Wait and retry with exponential backoff. |
INTERNAL_ERROR | 500 | An unexpected internal error occurred. |
SERVICE_UNAVAIL | 503 | The service is temporarily unavailable. |
CONFIG_NOT_READY | 503 | A required system configuration is not yet initialized. |
Authentication Errors
| Code | HTTP Status | Description |
|---|---|---|
INVALID_TOKEN | 401 | The access token is invalid or malformed. |
TOKEN_EXPIRED | 401 | The access token has expired. Use the refresh token to obtain a new one. |
INVALID_CREDENTIALS | 401 | The provided email or password is incorrect. |
PASSWORD_NOT_SET | 401 | No password has been set for this account (e.g., OAuth-only accounts). |
Resource Errors
| Code | HTTP Status | Description |
|---|---|---|
RESOURCE_NOT_FOUND | 404 | The requested resource (model, API key, user, etc.) does not exist. |
RESOURCE_EXISTS | 409 | A resource with the same identifier already exists. |
MODEL_IN_USE | 409 | The model cannot be deleted because it is bound to active channels. |
PROVIDER_HAS_MODELS | 409 | The provider cannot be deleted because it still has associated models. |
Validation Errors
| Code | HTTP Status | Description |
|---|---|---|
VALIDATION_FAILED | 422 | Request parameter validation failed. Check the error.detail field for specifics. |
INVALID_BODY | 400 | The request body is invalid or cannot be parsed. |
INVALID_QUERY | 400 | One or more query parameters are invalid. |
INVALID_PARAMETER | 400 | A specific parameter value is invalid. |
MISSING_PARAMETER | 400 | A required parameter is missing. |
EMPTY_UPDATE | 400 | The update request contains no fields to modify. |
PAYLOAD_TOO_LARGE | 413 | The request payload exceeds the maximum allowed size. |
Business Errors
| Code | HTTP Status | Description |
|---|---|---|
INSUFFICIENT_BALANCE | 400 (Web API) / 402 (Proxy) | Your account balance is too low to process this request. Top up your balance in the Console. Web API endpoints return HTTP 400; proxy endpoints (/v1/responses, /v1/messages, /v1beta/models/*) return HTTP 402. |
SELF_OPERATION | 400 | You cannot perform this operation on your own account (e.g., an admin cannot delete themselves). |
CAPTCHA_FAILED | 400 | The CAPTCHA verification failed. Please try again. |
OTP_INVALID | 400 | The provided one-time password (OTP) code is invalid or expired. |
Proxy Gateway Errors
When using the proxy endpoints (/v1/responses, /v1/messages, /v1beta/models/*), errors are returned in the provider-specific format rather than the standard Web API format. The HTTP status codes indicate the error type:
| HTTP Status | Meaning | OpenAI Error Type | Anthropic Error Type | Gemini Error Status |
|---|---|---|---|---|
| 400 | Bad request | invalid_request_error | invalid_request_error | INVALID_ARGUMENT |
| 401 | Invalid API key | invalid_request_error | authentication_error | UNAUTHENTICATED |
| 402 | Insufficient balance | billing_error | billing_error | RESOURCE_EXHAUSTED |
| 403 | Quota exceeded | invalid_request_error | permission_error | PERMISSION_DENIED |
| 404 | Not found | invalid_request_error | not_found_error | NOT_FOUND |
| 429 | Rate limit exceeded | rate_limit_error | rate_limit_error | RESOURCE_EXHAUSTED |
| 5xx | Server error | api_error | api_error | INTERNAL |
HTTP Status Codes
OpenModel uses standard HTTP status codes:
| Status | Meaning |
|---|---|
| 200 | OK -- Request succeeded. |
| 400 | Bad Request -- Invalid request parameters. |
| 401 | Unauthorized -- Invalid or missing API key. |
| 402 | Payment Required -- Insufficient balance. |
| 403 | Forbidden -- Permission denied. |
| 404 | Not Found -- Resource does not exist. |
| 405 | Method Not Allowed -- HTTP method not supported for this endpoint. |
| 409 | Conflict -- Resource conflict (e.g., duplicate or in use). |
| 413 | Payload Too Large -- Request body exceeds the size limit. |
| 422 | Unprocessable Entity -- Validation failed. |
| 429 | Too Many Requests -- Rate limit exceeded. |
| 500 | Internal Server Error -- Unexpected server error. |
| 502 | Bad Gateway -- Upstream provider error. |
| 504 | Gateway Timeout -- Upstream provider timeout. |
Handling Errors
Retry Strategy
For transient errors (429, 500, 502, 503, 504), implement exponential backoff with jitter:
import time
import random
from openai import OpenAI, APIError, RateLimitError
client = OpenAI(
base_url="https://api.openmodel.ai/v1",
api_key="your-api-key",
)
def create_with_retry(max_retries=3):
for attempt in range(max_retries):
try:
return client.responses.create(
model="gpt-5.4",
input="Hello, world!",
)
except RateLimitError:
if attempt == max_retries - 1:
raise
wait = (2 ** attempt) + random.random()
print(f"Rate limited, retrying in {wait:.1f}s...")
time.sleep(wait)
except APIError as e:
if e.status_code in (500, 502, 503, 504) and attempt < max_retries - 1:
wait = (2 ** attempt) + random.random()
print(f"Provider error, retrying in {wait:.1f}s...")
time.sleep(wait)
else:
raise
response = create_with_retry()Best Practices
- Check error codes programmatically -- Use
error.code(Web API) or the format-specific error types (Proxy API) for control flow, not the human-readable message. - Implement exponential backoff -- For rate limits (429) and server errors (500, 502, 503, 504), wait with increasing delays between retries.
- Set reasonable timeouts -- Configure client-side timeouts to handle slow upstream providers gracefully.
- Monitor your usage -- Use the Dashboard to track your API key usage and set up alerts before hitting rate limits or running out of balance.
- Log error responses -- Record the full error response for debugging purposes, especially for intermittent issues.