Errors
What an error looks like, how the SDK raises it, and when to retry.
Every failed API call returns the same JSON shape and a standard HTTP status. The turns each into a Python exception, so your code handles a meaning, not a number.
The error body
Errors follow RFC 9457 and are sent as application/problem+json:
{
"type": "https://klarety.ai/problems/too-many-requests",
"title": "Too many requests",
"status": 429,
"detail": "slow down and retry in 12s",
"instance": "/v1/sql"
}| Field | Meaning |
|---|---|
type | A stable address for this kind of problem. Safe to branch on. |
title | A short summary. |
status | The HTTP status. |
detail | What happened, in words you can show or log. |
instance | The path that was called. |
credits | When present: what the refused action would cost, so a person can agree to the price and ask again. |
limit | When present: the plan limit that refused it, so a person can ask for it to be raised. |
Status codes
| Status | Meaning | Retry? |
|---|---|---|
401 | Sign-in failed: no token, a wrong or expired token, or a rejected key. The body is the same for every cause. | No. Fix the key or get a new token. |
402 | The cannot pay for this work. | After adding credits. |
403 | You are signed in, but this is out of scope for your key or role. | No. |
404 | Not found, or not yours to see. | No. |
409 | It changed since you read it, or is changing. | Read again, then retry. |
413 | The request body is too large (over 1 MiB). | No. Send less, or upload a file. |
422 | The request is not one you may make, or is invalid. | No. Fix the request. |
429 | Too many requests, or every slot is busy. Nothing ran. | Yes, after Retry-After seconds. |
500 | Something failed on our side. The body carries no detail. | Yes, a little later. |
503 | Temporarily unavailable, for example while Nexus starts. | Yes, after Retry-After when present. |
How the SDK raises them
All SDK exceptions inherit from KlaretyError, and you import them from klarety.
| Exception | Raised for |
|---|---|
AuthError | 401, and a key rejected at Nexus.connect(). |
RefusedError | 403 and 422. |
TableRuleError | A change that breaks a rule of the table (a kind of RefusedError). Never resend it unchanged. |
NotFoundError | 404. |
ConflictError | 409. |
InsufficientCreditsError | 402. |
OverBudgetError | 413, 429, and a query that would read more than your plan allows. |
RateLimitedError | More calls per minute than your plan allows (a kind of OverBudgetError). |
ServiceError | 500, 503 and anything else on our side. |
AnswerNotReadyError | No answer in the time allowed, often while Nexus starts (a kind of ServiceError). |
SparkStartingError | is starting for your workspace (a kind of AnswerNotReadyError). |
WaitingForOwnerError | A change is held for the owner's OK. Carries job_id. Never resend it. |
A careful handler
from klarety import (
AuthError,
ConflictError,
InsufficientCreditsError,
KlaretyError,
Nexus,
OverBudgetError,
RefusedError,
ServiceError,
)
try:
with Nexus.connect() as nexus:
result = nexus.sql("SELECT COUNT(*) AS n FROM orders")
print(result.rows)
except AuthError:
print("Sign-in failed: check or replace the API key.")
except InsufficientCreditsError:
print("Out of credits.")
except OverBudgetError as over:
print(f"Over a plan limit or rate: {over}")
except RefusedError as refused:
print(f"Not allowed: {refused}")
except ConflictError:
print("Changed since read: read again, then retry.")
except ServiceError as failed:
print(f"Klarety could not answer, try later: {failed}")
except KlaretyError as other:
print(f"Klarety error: {other}")Order matters: catch the more specific exceptions first.
What the SDK retries for you
You rarely need your own retry loop.
- Reads (
GET) are retried up to three times on502,503and504, with a short backoff. - Busy and rate-limited answers are waited out on any call, honouring
Retry-After, for up to five minutes. Nothing ran, so this is safe. - SQL statements carry an ID, so a resent statement runs once.
- Other writes (
POST,PUT,PATCH,DELETE) are never retried, because replaying one could spend credits twice.
Retrying with raw HTTP
If you call the API directly:
- Retry only on
429,503and500. - Wait the
Retry-Afterheader's seconds when it is present; otherwise back off with random jitter. - Retry a write only if it is safe to run twice, or carries its own ID (
statement_idon/v1/sql,write_idon row edits).
Next steps
- Limits and rate limits to see what triggers
429and413. - Authentication for
401. - API reference for every endpoint.