Error response shape
Every non-2xx response has the same envelope:
| Field | Purpose |
|---|---|
type | OpenAI-compatible category (invalid_request_error, authentication_error, rate_limit_error, api_error) |
code | Machine-readable sub-code (see SchneeAI-specific codes) |
message | Human-readable explanation |
param | Offending parameter, if applicable |
request_id | Include this when contacting support — we can trace the exact call |
HTTP status → action
| Status | Meaning | Retry? | Action |
|---|---|---|---|
| 400 | Malformed JSON or missing required field | No | Fix the request body |
| 401 | API key invalid or missing | No | Check the Authorization header |
| 403 | Tenant scope or role forbidden | No | Verify tenant and role on the token |
| 404 | model or prompt name not found | No | Check the Model Directory |
| 422 | Valid JSON but semantically rejected | No | Read error.code — usually context length, unsupported parameter, or content policy |
| 429 | Rate limit or budget exceeded | Yes (with backoff) | Honor Retry-After if present |
| 500 | Internal Gateway error | Yes | Exponential backoff |
| 502 | Upstream provider error | Yes | Exponential backoff |
| 503 | Gateway temporarily unavailable | Yes | Exponential backoff |
| 504 | Upstream provider timeout | Yes | Exponential backoff |
SchneeAI-specific error codes
The OpenAI-compatible envelope carries SchneeAI-specific sub-codes in error.code. The ones you will actually hit:
| Code | HTTP | Meaning |
|---|---|---|
budget_exceeded | 429 | The tenant or feature budget is exhausted. Retry only after the budget resets (next hour / day / month, depending on the policy). |
pii_detected | 422 | Your tenant’s PII policy is set to block and the scanner found a critical category. Redact the input or switch the policy to mask / flag. |
context_length_exceeded | 422 | The combined prompt + max_tokens exceeds the model’s context window. Truncate or switch to a longer-context model. |
unsupported_parameter | 422 | The selected provider does not support a parameter you sent (e.g., temperature with reasoning models). |
provider_error | 502 | The upstream LLM provider returned an error. Retry with backoff. |
Retry strategy
Retry only on 429, 500, 502, 503, 504. Use exponential backoff with jitter:
wait = min(base * 2^attempt, max_wait) + random_jitter
base = 1 second
max_wait = 60 seconds
jitter = 0–25% of wait
attempts = max 5
Honor the Retry-After header when present. 429 responses include it as an integer number of seconds.
When not to retry
- 400 / 401 / 403 / 404 / 422 — the request itself is wrong; retrying produces the same error.
- 429 with
code: budget_exceeded— retrying burns the budget faster. Wait for the reset window.
Idempotency
For POST /v1/chat/completions, send an Idempotency-Key header so retries do not double-charge or double-count:
- Format: any string ≤ 255 chars. UUIDv4 recommended.
- TTL: 24 hours. After that the same key is treated as a new request.
- Scope: scoped to your service + tenant, so two tenants using the same key do not collide.
- What is deduplicated: the charge and the usage record. The actual LLM call still happens if the original request never reached the provider.
Client examples
Python (requests + tenacity)
pass
=
return
TypeScript (fetch)
Go (net/http + backoff)
var buf bytes.Buffer
json.NewEncoder(&buf).Encode(map[string]any)
req, _ := http.NewRequest("POST", "https://api.schneeai.com/v1/chat/completions", &buf)
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Idempotency-Key", uuid.NewString())
req.Header.Set("Content-Type", "application/json")
bo := backoff.NewExponentialBackOff()
bo.MaxElapsedTime = 60 * time.Second
backoff.Retry(func() error , bo)
Support
If an error persists after correct retrying, email [email protected] with the request_id from the error response. We can trace the exact call within minutes.
Note: SchneeAI is in design-partner stage. The error envelope above is stable and OpenAI-compatible; the budget / PII sub-codes are aligned with the platform features currently shipping. If you hit a code not listed here, send us the request_id and we will document it.