Error Handling
The Ashr Labs SDK provides specific exception classes for different error scenarios, making it easy to handle errors gracefully.
Exception Hierarchy
AshrLabsError (base)
├── AuthenticationError (401)
├── AuthorizationError (403)
├── NotFoundError (404)
├── ValidationError (422)
├── RateLimitError (429)
└── ServerError (5xx)
Exception Classes
AshrLabsError
Base exception for all SDK errors.
Properties:
message(string): Error messagestatusCode(number | null): HTTP status code if applicableresponse(Record<string, unknown> | null): Raw response body if available
import { AshrLabsError } from "ashr-labs";
try {
const result = await client.getDataset(42);
} catch (e) {
if (e instanceof AshrLabsError) {
console.log(`Error: ${e.message}`);
console.log(`Status Code: ${e.statusCode}`);
console.log(`Response: ${JSON.stringify(e.response)}`);
}
}
AuthenticationError
Raised when API key authentication fails (HTTP 401).
Common causes:
- Invalid API key
- Expired API key
- Revoked API key
- Malformed Authorization header
import { AuthenticationError } from "ashr-labs";
try {
const datasets = await client.listDatasets();
} catch (e) {
if (e instanceof AuthenticationError) {
console.log("Authentication failed!");
console.log("Please check your API key is valid and not expired.");
// Log the user out or prompt for new credentials
}
}
AuthorizationError
Raised when the API key lacks permission (HTTP 403).
Common causes:
- Trying to access a resource in a different tenant
- Using API key for OAuth-only endpoints
- Insufficient scopes on the API key
import { AuthorizationError } from "ashr-labs";
try {
// Attempting to access another tenant's data
const dataset = await client.getDataset(999);
} catch (e) {
if (e instanceof AuthorizationError) {
console.log("Access denied!");
console.log("You don't have permission to access this resource.");
}
}
NotFoundError
Raised when a requested resource doesn't exist (HTTP 404).
Common causes:
- Invalid resource ID
- Resource was deleted
- Typo in the ID
import { NotFoundError } from "ashr-labs";
try {
const dataset = await client.getDataset(99999);
} catch (e) {
if (e instanceof NotFoundError) {
console.log(`Dataset not found: ${e.message}`);
// Handle missing resource gracefully
}
}
ValidationError
Raised when request validation fails (HTTP 422).
Common causes:
- Missing required fields
- Invalid field types
- Schema validation failure
- Invalid parameter values
import { ValidationError } from "ashr-labs";
try {
const run = await client.createRun(-1, {}); // Invalid ID
} catch (e) {
if (e instanceof ValidationError) {
console.log(`Validation failed: ${e.message}`);
// Show user which fields need correction
}
}
RateLimitError
Raised when rate limits are exceeded (HTTP 429).
Common causes:
- Too many requests in a short period
- Burst limit exceeded
import { RateLimitError } from "ashr-labs";
async function fetchWithRetry(
client: AshrLabsClient,
datasetId: number,
maxRetries = 3,
) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.getDataset(datasetId);
} catch (e) {
if (e instanceof RateLimitError && attempt < maxRetries - 1) {
const waitTime = 2 ** attempt * 1000; // Exponential backoff
console.log(`Rate limited. Waiting ${waitTime}ms...`);
await new Promise((r) => setTimeout(r, waitTime));
} else {
throw e;
}
}
}
}
ServerError
Raised when the server encounters an internal error (HTTP 5xx).
Common causes:
- Server maintenance
- Temporary outage
- Internal service failure
import { ServerError } from "ashr-labs";
try {
const datasets = await client.listDatasets();
} catch (e) {
if (e instanceof ServerError) {
console.log("Server error occurred. Please try again later.");
// Log the error for monitoring
console.error(`Server error: ${e.statusCode} - ${e.message}`);
}
}
Best Practices
1. Catch Specific Exceptions
Always catch the most specific exception first:
import {
AshrLabsClient,
AuthenticationError,
AuthorizationError,
NotFoundError,
ValidationError,
RateLimitError,
ServerError,
AshrLabsError,
} from "ashr-labs";
try {
const dataset = await client.getDataset(42);
} catch (e) {
if (e instanceof AuthenticationError) {
// Handle auth failure - maybe refresh credentials
handleAuthFailure();
} else if (e instanceof AuthorizationError) {
// Handle permission denied
showPermissionError();
} else if (e instanceof NotFoundError) {
// Handle missing resource
showNotFoundMessage();
} else if (e instanceof ValidationError) {
// Handle validation errors
showValidationErrors(e.response);
} else if (e instanceof RateLimitError) {
// Handle rate limiting
scheduleRetry();
} else if (e instanceof ServerError) {
// Handle server errors
showTemporaryError();
} else if (e instanceof AshrLabsError) {
// Catch-all for other API errors
logUnexpectedError(e);
} else {
throw e;
}
}
2. Implement Retry Logic
For transient errors, implement retry with exponential backoff:
import { RateLimitError, ServerError, AshrLabsError } from "ashr-labs";
async function robustRequest<T>(
fn: () => Promise<T>,
maxRetries = 3,
): Promise<T> {
let lastError: Error | null = null;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (e) {
if (e instanceof RateLimitError || e instanceof ServerError) {
lastError = e;
if (attempt < maxRetries - 1) {
const waitTime = 2 ** attempt * 1000 + Math.random() * 100;
await new Promise((r) => setTimeout(r, waitTime));
continue;
}
}
// Don't retry auth/validation/not-found errors
throw e;
}
}
throw lastError;
}
// Usage
const dataset = await robustRequest(() => client.getDataset(42));
3. Log Errors Appropriately
try {
const result = await client.createRun(42, runData);
} catch (e) {
if (e instanceof AuthenticationError) {
console.error(`Auth failed: ${e.message}`);
throw e;
} else if (e instanceof ValidationError) {
console.warn(`Validation error: ${e.message}`, { response: e.response });
throw e;
} else if (e instanceof ServerError) {
console.error(`Server error ${e.statusCode}: ${e.message}`);
throw e;
}
}
4. User-Friendly Error Messages
Map technical errors to user-friendly messages:
import {
AuthenticationError,
AuthorizationError,
NotFoundError,
ValidationError,
RateLimitError,
ServerError,
AshrLabsError,
} from "ashr-labs";
function getUserMessage(error: unknown): string {
if (error instanceof AuthenticationError)
return "Your session has expired. Please log in again.";
if (error instanceof AuthorizationError)
return "You don't have permission to perform this action.";
if (error instanceof NotFoundError)
return "The requested item could not be found.";
if (error instanceof ValidationError)
return "Please check your input and try again.";
if (error instanceof RateLimitError)
return "Too many requests. Please wait a moment and try again.";
if (error instanceof ServerError)
return "We're experiencing technical difficulties. Please try again later.";
return "An unexpected error occurred.";
}
5. Wrapper Functions for Cleanup
async function safeApiOperation<T>(
operationName: string,
fn: () => Promise<T>,
): Promise<T> {
try {
return await fn();
} catch (e) {
if (e instanceof AshrLabsError) {
console.error(`${operationName} failed: ${e}`);
// Perform any necessary cleanup
}
throw e;
}
}
// Usage
const run = await safeApiOperation("Create Run", () =>
client.createRun(42, runData),
);
Network Errors
The SDK also handles network-level errors:
import { AshrLabsError } from "ashr-labs";
try {
const result = await client.healthCheck();
} catch (e) {
if (e instanceof AshrLabsError) {
if (e.message.includes("Network error")) {
console.log("Cannot connect to the API. Check your internet connection.");
} else if (e.message.toLowerCase().includes("timed out")) {
console.log("Request timed out. The server may be slow or unreachable.");
} else {
throw e;
}
}
}
Debugging Tips
Check the raw response in exceptions:
try {
const result = await client.getDataset(42);
} catch (e) {
if (e instanceof AshrLabsError) {
console.log(`Status: ${e.statusCode}`);
console.log(`Message: ${e.message}`);
console.log(`Raw response: ${JSON.stringify(e.response)}`);
}
}
The toString() method on errors provides a formatted summary:
try {
await client.getDataset(99999);
} catch (e) {
if (e instanceof AshrLabsError) {
console.log(e.toString());
// => "[404] Dataset not found"
}
}