Error Hierarchy
ComplianceError (base)
├── ValidationError # Input validation failures
├── APIError # Server/network errors
│ ├── NotFoundError
│ ├── UnauthorizedError
│ ├── ForbiddenError
│ ├── RateLimitError
│ ├── ServerError
│ ├── NetworkError
│ └── TimeoutError
└── UploadError # File upload failures
├── FileTooLargeError
├── UploadTimeoutError
├── InvalidFileTypeError
├── UploadAbortedError
└── UploadUrlExpiredError
Basic Error Handling
import {
ComplianceError,
ValidationError,
NotFoundError,
UnauthorizedError,
} from "@artu-ai/compliance-sdk";
try {
const client = await sdk.clients.retrieve("client_123");
} catch (error) {
if (error instanceof NotFoundError) {
console.log("Client not found");
} else if (error instanceof UnauthorizedError) {
console.log("Invalid API key");
} else if (error instanceof ValidationError) {
console.log("Validation errors:", error.issues);
} else if (error instanceof ComplianceError) {
console.log("SDK error:", error.message);
} else {
throw error; // Re-throw unexpected errors
}
}
Error Properties
All errors extendComplianceError with these properties:
interface ComplianceError extends Error {
message: string; // Human-readable message
code: string; // Error code (e.g., "NOT_FOUND")
cause?: Error; // Original error if wrapped
toJSON(): object; // Serializable representation
}
Validation Errors
Validation errors occur when input data fails schema validation:import { ValidationError } from "@artu-ai/compliance-sdk";
try {
await sdk.clients.create({
type: "invalid_type",
name: "",
});
} catch (error) {
if (error instanceof ValidationError) {
console.log("Validation failed:");
for (const issue of error.issues) {
console.log(` ${issue.path.join(".")}: ${issue.message}`);
}
// Output:
// type: Invalid enum value
// name: String must contain at least 1 character
}
}
Validation Issue Structure
interface ValidationIssue {
path: (string | number)[]; // Path to the invalid field
message: string; // Human-readable error message
code: string; // Zod error code
}
API Errors
API errors include HTTP status information:import { APIError, isAPIError } from "@artu-ai/compliance-sdk";
try {
await sdk.clients.create({ ... });
} catch (error) {
if (isAPIError(error)) {
console.log("Status:", error.statusCode);
console.log("Code:", error.code);
console.log("Message:", error.message);
}
}
Not Found Error
import { NotFoundError } from "@artu-ai/compliance-sdk";
try {
await sdk.clients.retrieve("nonexistent_id");
} catch (error) {
if (error instanceof NotFoundError) {
console.log("Resource not found");
console.log("ID:", error.resourceId);
}
}
Unauthorized Error
import { UnauthorizedError } from "@artu-ai/compliance-sdk";
try {
await sdk.clients.list();
} catch (error) {
if (error instanceof UnauthorizedError) {
console.log("Authentication failed - check your API key");
}
}
Forbidden Error
import { ForbiddenError } from "@artu-ai/compliance-sdk";
try {
await sdk.alerts.generate({ ... });
} catch (error) {
if (error instanceof ForbiddenError) {
console.log("Access denied - insufficient permissions");
}
}
Rate Limit Error
import { RateLimitError } from "@artu-ai/compliance-sdk";
try {
await sdk.clients.list();
} catch (error) {
if (error instanceof RateLimitError) {
const retryAfter = error.retryAfter;
console.log(`Rate limited. Retry after ${retryAfter} seconds`);
// Wait and retry
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
await sdk.clients.list();
}
}
Server Error
import { ServerError } from "@artu-ai/compliance-sdk";
try {
await sdk.clients.list();
} catch (error) {
if (error instanceof ServerError) {
console.log("Server error - try again later");
console.log("Request ID:", error.requestId);
}
}
Network Error
import { NetworkError } from "@artu-ai/compliance-sdk";
try {
await sdk.clients.list();
} catch (error) {
if (error instanceof NetworkError) {
console.log("Network error - check your connection");
}
}
Timeout Error
import { TimeoutError } from "@artu-ai/compliance-sdk";
try {
await sdk.clients.list();
} catch (error) {
if (error instanceof TimeoutError) {
console.log("Request timed out");
}
}
Upload Errors
Handle file upload failures:import {
UploadError,
FileTooLargeError,
InvalidFileTypeError,
UploadTimeoutError,
UploadAbortedError,
UploadUrlExpiredError,
isUploadError,
} from "@artu-ai/compliance-sdk";
try {
await sdk.documents.upload({ ... });
} catch (error) {
if (error instanceof FileTooLargeError) {
console.log(`File exceeds maximum size of ${error.maxSize} bytes`);
} else if (error instanceof InvalidFileTypeError) {
console.log(`Invalid file type: ${error.mimeType}`);
console.log(`Allowed types: ${error.allowedTypes.join(", ")}`);
} else if (error instanceof UploadTimeoutError) {
console.log("Upload timed out");
} else if (error instanceof UploadAbortedError) {
console.log("Upload was aborted");
} else if (error instanceof UploadUrlExpiredError) {
console.log("Upload URL expired - request a new one");
} else if (isUploadError(error)) {
console.log(`Upload failed at stage: ${error.stage}`);
}
}
Type Guards
Use type guards for cleaner error handling:import { isAPIError, isUploadError } from "@artu-ai/compliance-sdk";
try {
await someOperation();
} catch (error) {
if (isAPIError(error)) {
// Handle API errors
} else if (isUploadError(error)) {
// Handle upload errors
}
}
Error Serialization
All errors can be serialized to JSON:try {
await sdk.clients.create({ ... });
} catch (error) {
if (error instanceof ComplianceError) {
const json = error.toJSON();
console.log(JSON.stringify(json, null, 2));
// {
// "name": "ValidationError",
// "message": "Invalid input",
// "code": "VALIDATION_ERROR",
// "issues": [...]
// }
}
}
Best Practices
Catch Specific Errors First
try {
await sdk.clients.retrieve(id);
} catch (error) {
// Catch specific errors first
if (error instanceof NotFoundError) {
return null;
}
if (error instanceof UnauthorizedError) {
await refreshToken();
return sdk.clients.retrieve(id);
}
// Then catch base error
if (error instanceof ComplianceError) {
logger.error("SDK error", error.toJSON());
}
throw error;
}
Retry with Backoff
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (error instanceof RateLimitError) {
await new Promise((r) => setTimeout(r, error.retryAfter * 1000));
} else if (
error instanceof NetworkError ||
error instanceof TimeoutError
) {
await new Promise((r) => setTimeout(r, attempt * 1000));
} else {
throw error;
}
}
}
throw new Error("Max retries exceeded");
}
const client = await withRetry(() => sdk.clients.retrieve(id));
