Error Handling
Response Pattern
Every Sarna API response follows this structure. Check fields in this order:
Errorsarray — if non-empty, the operation failedWarningsarray — informational; log for operational visibilityHasData— iffalse, no results found (not an error)- Business data — the actual response payload
{
"Errors": [],
"Warnings": [{"Code": "LOW_BALANCE", "Message": "Account balance below $10,000"}],
"HasData": true,
"Quote": { "Symbol": "AAPL", "Last": 150.00 }
}
Common Error Codes
| HTTP Status | Error Code | Resolution |
|---|---|---|
| 401 | UNAUTHORIZED | Check Bearer token format and validity |
| 403 | ADMIN_PERMISSION_REQUIRED | Request admin access from your administrator |
| 400 | INSUFFICIENT_BUYING_POWER | Check GET /balances/account/id/{id} before ordering |
| 400 | INVALID_SYMBOL | Use POST /search to find valid symbols |
| 429 | RATE_LIMITED | Implement exponential backoff; check Retry-After header |
gRPC Status Code Mapping
| gRPC Status | HTTP Status | Meaning |
|---|---|---|
| OK (0) | 200 | Success |
| INVALID_ARGUMENT (3) | 400 | Bad request parameters |
| UNAUTHENTICATED (16) | 401 | Invalid credentials |
| PERMISSION_DENIED (7) | 403 | Insufficient permissions |
| NOT_FOUND (5) | 404 | Resource not found |
| RESOURCE_EXHAUSTED (8) | 429 | Rate limited |
| INTERNAL (13) | 500 | Server error |
Retry Strategy
For transient errors (429, 500, 503):
- Wait for
Retry-Afterheader value (if present) - Otherwise use exponential backoff: 1s, 2s, 4s, 8s, 16s
- Add jitter (random 0-1s) to avoid thundering herd
- Max 5 retries, then fail
Do not retry 400, 401, or 403 errors — these require fixing the request.