API errors and how to handle them
This page lets you write error handling once and get it right. At the end you will have a copy-pasteable handler that distinguishes a bad key from an empty wallet from a rate limit, and know which failures are worth retrying.
The error envelope
Errors raised by the SynapseX API itself — a bad key, an empty wallet, a missing scope, a malformed body — use the OpenAI-style envelope:
{"error":{"message":"…","type":"…"}}Not every error body has that shape. When the failure comes from the model
gateway behind the API — a refused model id, a rate limit — the gateway’s own
response is forwarded to you verbatim, with its original status code and a
body shaped {"detail": "…"} instead. Branch your error handling on the
HTTP status code, and read error.message when it is present, falling
back to detail.
The type values raised by the API itself on /chat/completions and /models
are:
type | HTTP status | Meaning |
|---|---|---|
authentication_error | 401 | The key is missing, malformed, invalid or expired |
insufficient_quota | 402 | The workspace has no credits |
permission_error | 403 | The key lacks the chat:write scope |
invalid_request_error | 400 | The request body is missing something required |
server_error | 502 / 503 | SynapseX or an upstream service failed |
400 — invalid request
{"error":{"message":"model and messages are required","type":"invalid_request_error"}}Both model and messages are mandatory. Fix the request body; retrying will
not help.
401 — invalid or expired key
Two distinct bodies, both HTTP 401. With no Authorization header, or a header
that does not start with Bearer sk-synapsex-:
{"error":{"message":"Missing or invalid API key","type":"authentication_error"}}With a well-formed but unrecognised or expired key:
{"error":{"message":"Invalid or expired API key","type":"authentication_error"}}Fix: check that the header includes the literal Bearer prefix and the full
sk-synapsex- key, and that the key has not been deleted in the console. A key
is shown only once at creation, so if it was lost it must be replaced, not
recovered. See Authentication.
402 — insufficient credits
{"error":{"message":"Insufficient credits","type":"insufficient_quota"}}This is checked as part of authentication, before any model runs — you are not charged for the failed request, and no partial output is produced.
Fix: top up the workspace balance. See Credits and spending. Do not retry a 402 in a loop; nothing about retrying changes the balance.
403 — permission denied
{"error":{"message":"API key does not have chat:write scope","type":"permission_error"}}Fix: create a key with the default scope set, which includes chat:write.
A 403 can also mean the model you asked for is not available to API keys. In that case the refusal names the model rather than the scope, and it lists the ids that are available. Fix: read those ids out of the error message and use one of them.
Do not fix this by re-reading GET /api/v1/models — that endpoint returns the
whole catalog and is not filtered to what your key may call, so the id you were
just refused is still in it. See Models.
429 — rate limited
Fix: back off exponentially with jitter and cap the number of retries, so a sustained limit does not become an infinite loop.
Do not build against a Retry-After header on this API — the response your
client receives does not carry one. The only SynapseX header this API adds is
X-SynapseX-Request-Id, and only on /chat/completions responses that reached
the model gateway.
Specific per-key request or token limits are not published either, and you should not build against a number you inferred from observation. Treat 429 as “slow down”, not as a value you can read.
5xx and upstream failures
server_error with 502 or 503 means SynapseX or an upstream model service
failed or is unconfigured. These are the only errors worth retrying blindly:
retry with exponential backoff, a few times at most.
If the failing response carries an X-SynapseX-Request-Id header, keep it and
include it when you report the problem — it identifies the exact request. A 502
or 503 raised by SynapseX before your request reached the model gateway does not
carry one.
Python error handling with the SDK
The Python SDK raises a typed exception per status:
from synapsex_platform import (
LLMClient,
AuthenticationError,
InsufficientCreditsError,
PermissionDeniedError,
RateLimitError,
APIError,
)
client = LLMClient() # reads SYNAPSEX_API_KEY
try:
response = client.chat_completions(
model="synapsex-forge-code-14b-v1",
messages=[{"role": "user", "content": "Hello!"}],
)
print(response["choices"][0]["message"]["content"])
except AuthenticationError:
raise SystemExit("Check SYNAPSEX_API_KEY - the key is missing or invalid.")
except InsufficientCreditsError:
raise SystemExit("Out of credits. Top up the workspace before retrying.")
except PermissionDeniedError as exc:
raise SystemExit(f"Not permitted: {exc}. Check the key scope and the model id.")
except RateLimitError:
... # back off and retry
except APIError as exc:
# Any other non-success status. exc.status_code and exc.payload are set.
raise SystemExit(f"Request failed ({exc.status_code}): {exc}")AuthenticationError, InsufficientCreditsError, PermissionDeniedError and
RateLimitError all subclass APIError, so catch the specific ones first.
The same handling with the stock OpenAI client
If you use the openai package instead, branch on the status code:
import openai
try:
response = client.chat.completions.create(
model="synapsex-forge-code-14b-v1",
messages=[{"role": "user", "content": "Hello!"}],
)
except openai.APIStatusError as exc:
if exc.status_code == 401:
raise SystemExit("Invalid SynapseX API key.")
if exc.status_code == 402:
raise SystemExit("Out of SynapseX credits.")
if exc.status_code == 403:
raise SystemExit("Missing chat:write scope, or the model is unavailable.")
if exc.status_code == 429:
... # back off and retry
raiseTroubleshooting table
| Symptom | Most likely cause | Action |
|---|---|---|
| 401 on every call | Missing Bearer prefix, or the key was deleted | Re-check the header; create a new key |
| Worked yesterday, 401 today | Key deleted or rotated | Issue a new key and redeploy |
| 402 immediately, no output | Workspace balance at or below zero | Add credits |
| 403 mentioning scope | Key created without chat:write | Create a new key with the default scope |
| 403 mentioning the model | Model not available to API keys | Use one of the ids listed in the error message itself |
400 model and messages are required | Body missing a required field | Send both model and messages |
| Parameter appears ignored | The field is not forwarded by the API | See the supported field list in Chat completions |
| 429 bursts | Sending too fast | Back off exponentially with jitter; there is no Retry-After header to read |
| Intermittent 502 / 503 | Upstream failure | Retry with backoff; report with X-SynapseX-Request-Id |