Errors
The HTTP status code carries the primary signal. The response body shape depends on the kind of failure: regular errors return {"detail": "<message>"}, request-validation failures return FastAPI's structured detail array.
Regular errors#
Anything raised through the normal exception path — auth rejected, permission denied, resource not found, conflict, rate-limit, server error — comes back as:
1 | |
The HTTP status code tells you the class. The detail string is human-readable; surface it in UIs or logs but don't parse it.
| Status | Class | When |
|---|---|---|
| 400 | Bad request | Malformed path or input that's not a schema-level validation failure |
| 401 | Unauthorized | Missing, invalid, expired, or wrong-issuer token |
| 403 | Forbidden | Authenticated but lacking permission; user suspended; ownership-only action |
| 404 | Not found | Resource doesn't exist, or isn't visible to the caller — we don't distinguish |
| 409 | Conflict | Name collision, version mismatch, already-in-state operations (e.g., invitation already used) |
| 410 | Gone | Soft-deleted resource; expired invitation, link, or upload session |
| 413 | Payload too large | Upload exceeds tenant's per-file size cap |
| 422 | Unprocessable | Pydantic schema validation failed — see next section |
| 429 | Rate limited | Honor Retry-After header where present |
| 500 | Internal | Unexpected server failure |
| 502 | Bad gateway | Upstream service unreachable (ScaiKey, S3, Weaviate, SMB/SharePoint connector source) |
| 503 | Service unavailable | Dependency drained or degraded; readiness probe failing |
| 504 | Gateway timeout | Upstream timed out |
| 507 | Insufficient storage | A quota would be exceeded — share, user, group, tenant, or partner level |
Validation errors (422)#
When a request body fails Pydantic validation, FastAPI returns its standard structured error with a list of issues. detail is an array, not a string:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Each entry has:
loc— a path from the request root to the failing field (e.g.,["body", "role"],["query", "limit"])msg— human-readable descriptiontype— the validator kind that fired (enum,missing,string_too_short, etc.)
Parse this on the client side to render field-level error messages.
Detecting the shape#
detail can be either a string or an array. The two shapes never appear together. Practical client code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
1 2 3 4 5 6 7 8 9 10 11 12 | |
Retry strategy#
| Status | Retry? | Notes |
|---|---|---|
| 401 | No | Refresh the token if AUTH_TOKEN_EXPIRED; otherwise fix credentials |
| 403 | No | User lacks permission — no amount of retrying will fix it |
| 404 | No | Resource doesn't exist |
| 409 | Maybe | Re-read current state, resolve, retry once. For sync conflicts, use the conflict-resolution API |
| 410 | No | Restore the resource or create a new one |
| 413 | No | Use resumable uploads for large files |
| 422 | No | Fix the request body |
| 429 | Yes | Honor Retry-After; exponential backoff with jitter |
| 500 | Once | Transient. Don't retry destructive operations without idempotency |
| 502, 503, 504 | Yes | Upstream issue; backoff and retry |
| 507 | No | Quota exceeded; free space or raise the quota |
Streaming errors#
For file downloads, an error after response headers are sent produces a truncated body — your client must verify the full Content-Length (or the file's checksum_sha256) before treating a stream as complete.
For WebSocket connections, errors typically arrive as connection-close codes. The custom close codes ScaiDrive uses:
| Code | Meaning |
|---|---|
| 4401 | Auth token invalid or missing |
| 4403 | User suspended or no permission to subscribe |
| 4429 | Connection limit hit (per-token or per-tenant) |
Standard WebSocket codes (1000, 1001, 1006, ...) carry their usual meaning.
Known gaps#
Two things this API doesn't have yet, worth knowing about:
- No machine-readable error codes. The
detailstring is the only error identifier. If you're building robust error handling, branch on HTTP status code + the operation you were performing, not on substring matching the message. - No request ID propagation. Responses don't include an
X-Request-Idheader or a body-level request identifier today. When filing support tickets, include the request timestamp, status code, full URL, and the error message — that's the highest-fidelity correlation we can offer right now.
Both are tracked as planned improvements; this page will be updated when they ship.
What's next#
- Rate Limiting — how 429s are produced and how to back off.
- Troubleshooting — what to check when specific status codes appear.