Errors
Error codes, formats, and handling guidance
Error Response Format
All errors follow a consistent format:
json
{
"error": "Invalid API key",
"code": "AUTH_FAILED",
"request_id": "req_abc123",
"docs_url": "https://docs.scalix.world/api-reference/errors#AUTH_FAILED"
}Error Codes
Authentication & Authorization
| Code | HTTP | Description |
|---|---|---|
AUTH_FAILED | 401 | Missing, expired, or malformed token |
FORBIDDEN | 403 | Insufficient scope or wrong tenant |
Request Errors
| Code | HTTP | Description |
|---|---|---|
BAD_REQUEST | 400 | Invalid request structure |
VALIDATION_ERROR | 422 | JSON parsing or type mismatch |
NOT_FOUND | 404 | Resource doesn't exist |
ALREADY_EXISTS | 409 | Duplicate constraint violation |
PAYLOAD_TOO_LARGE | 413 | Request body exceeds limit |
Rate Limiting
| Code | HTTP | Description |
|---|---|---|
RATE_LIMITED | 429 | Too many requests |
Check X-RateLimit-Reset header for when to retry.
Server Errors
| Code | HTTP | Description |
|---|---|---|
NOT_CONFIGURED | 501 | Feature not enabled for this project |
INTERNAL_ERROR | 500 | Unexpected server error |
BAD_GATEWAY | 502 | Backend service unavailable |
GATEWAY_TIMEOUT | 504 | Backend service didn't respond |
Auth-Specific Errors
| Code | HTTP | Description |
|---|---|---|
AUTH_FAILED | 401 | Sign-in failed. Returned identically for a wrong password, a non-existent account, and a locked account — the reason is deliberately not disclosed to prevent account enumeration and lockout probing. |
FORBIDDEN | 403 | Action not permitted for this account or token — includes an unverified email attempting a gated action. |
BAD_REQUEST | 400 | Malformed request, including a failed bot-prevention (captcha) check. |
Database-Specific Errors
| Code | HTTP | Description |
|---|---|---|
QUERY_BLOCKED | 403 | Query rejected by policy — a write with a read-only key, a forbidden DDL/schema change, or a firewall rule. |
QUERY_ERROR | 400 | Query failed to execute (syntax error, constraint violation, timeout, or other database error). |
Handling Errors
The TypeScript SDK returns a { data, error, response } envelope instead of
throwing:
typescript
import { executeSql } from "@scalix-world/sdk";
const { data, error, response } = await executeSql({
body: { query: "SELECT * FROM users" },
});
if (error) {
if (error.code === "AUTH_FAILED") {
// Refresh token or re-authenticate
} else if (error.code === "RATE_LIMITED") {
const resetAt = Number(response.headers.get("x-ratelimit-reset"));
await sleep(resetAt * 1000 - Date.now());
} else {
console.error(`Error ${error.code}: ${error.error}`);
}
}