Guide · Shared
Handle errors
Catch, classify, and recover from API and SDK errors gracefully. Covers error classes, retry strategies, and user-facing error messages.
Overview
The Ananke Labs API returns structured error responses. The TypeScript SDK wraps these as typed error classes so you can catch and handle them programmatically. This guide covers every error pattern you'll encounter.
Error classes
| Class | HTTP status | When thrown |
|---|---|---|
AnankeFieldValidationError | 400 | Request body fails schema or field validation. |
AnankeApiError (UNAUTHORIZED) | 401 | Missing or malformed API key. |
AnankeApiError (FORBIDDEN) | 403 | Key valid but quota/entitlement check failed. |
AnankeApiError (NOT_FOUND) | 404 | Resource not found under this tenant. |
AnankeApiError (CONFLICT) | 409 | Duplicate detection or invalid lifecycle transition. |
AnankeApiError (UNPROCESSABLE) | 422 | Semantic error (archived template, schema mismatch). |
AnankeApiError (RATE_LIMITED) | 429 | Rate limit exceeded. |
AnankeApiError (SERVICE_UNAVAILABLE) | 503 | Upstream dependency unavailable. |
Catching errors
Catch and classify errors
import { AnankeApiError, AnankeFieldValidationError } from "@ananke/sdk";
try {
const doc = await client.trust.documents.issue({ /* ... */ });
} catch (err) {
if (err instanceof AnankeFieldValidationError) {
// 400 - inspect individual field errors
console.error("Validation failed:");
for (const field of err.fieldErrors) {
console.error(` ${field.field}: ${field.message}`);
}
} else if (err instanceof AnankeApiError) {
switch (err.code) {
case "UNAUTHORIZED":
console.error("Check your API key");
break;
case "FORBIDDEN":
console.error("Quota exhausted or tenant suspended");
break;
case "NOT_FOUND":
console.error("Resource not found:", err.message);
break;
case "CONFLICT":
console.error("Duplicate or invalid transition:", err.message);
break;
case "RATE_LIMITED":
console.error("Rate limited — retry after delay");
break;
case "SERVICE_UNAVAILABLE":
console.error("Service temporarily unavailable");
break;
default:
console.error("API error:", err.code, err.message);
}
} else {
// Network error, timeout, etc.
console.error("Unexpected error:", err);
}
}HTTP status codes
When using raw HTTP (no SDK), check the response status:
| Status | Meaning | Action |
|---|---|---|
200 / 201 | Success | Process the response body. |
400 | Validation error | Fix the request body. Check errors array in response. |
401 | Unauthorized | Check x-api-key header. |
403 | Forbidden | Check tenant status and entitlements. |
404 | Not found | Verify the resource ID/reference. |
409 | Conflict | Handle duplicate or invalid transition. |
429 | Rate limited | Back off and retry. |
503 | Service unavailable | Retry after delay. |
Field validation errors
The 400 response includes a structured errors array:
400 response body
{
"status": 400,
"code": "VALIDATION_ERROR",
"message": "One or more fields failed validation.",
"errors": [
{ "field": "recipientEmail", "message": "Must be a valid email address." },
{ "field": "fields[0].value", "message": "Required field 'certNumber' is missing." }
]
}Retry strategy
Use the SDK's built-in retry for transient errors:
SDK retry configuration
const client = new AnankeClient({
apiKey: process.env.ANANKE_API_KEY!,
retries: 3, // retry up to 3 times on 429 / 5xx
retryDelayMs: 500, // initial delay (exponential backoff)
});For manual retry logic with raw HTTP:
429— Wait for the delay indicated in theRetry-Afterheader.503— Use exponential backoff: 500ms, 1s, 2s, 4s.400,401,403,404,409— Do not retry. These are client errors.
User-facing messages
Never show raw error codes to end users. Map them to friendly messages:
| Code | User message |
|---|---|
UNAUTHORIZED | "Authentication failed. Please check your credentials." |
FORBIDDEN | "You don't have permission for this action." |
NOT_FOUND | "The requested resource was not found." |
RATE_LIMITED | "Too many requests. Please wait and try again." |
SERVICE_UNAVAILABLE | "The service is temporarily unavailable. Please try again later." |
Raw API error structure
Standard error response
{
"status": 404,
"code": "NOT_FOUND",
"message": "No issuance found with id 'abc-123' under this tenant.",
"traceId": "00-abc123..."
}The traceId is useful for debugging. Include it in support requests.
Next steps
- Secure your integration — Production hardening.
- API error reference — Complete error catalogue.
- Rate limits — Understand request limits.