Error Handling
Handle errors gracefully with typed error classes and comprehensive error information.
Error Types
The SDK throws specific error classes for different failure scenarios:
typescript
import {
AuthenticationError,
RateLimitError,
ValidationError,
NotFoundError,
APIError
} from '@myxara/sdk-js'Basic Error Handling
typescript
try {
await client.inboxes.create({
local_part: 'support',
name: 'Support Agent'
})
} catch (error) {
if (error instanceof APIError) {
console.error('API Error:', error.message)
console.error('Status:', error.status)
} else {
console.error('Unexpected error:', error)
}
}Authentication Errors
Thrown when API key is invalid or missing:
typescript
import { AuthenticationError } from '@myxara/sdk-js'
try {
await client.inboxes.list()
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Authentication failed')
console.error('Status:', error.status) // 401
console.error('Message:', error.message)
// → "Invalid API key"
// Check your API key
console.log('Current key:', process.env.MYXARA_API_KEY)
}
}Common Causes
- API key not set in environment variables
- API key has been revoked
- API key doesn't have required scopes
- Typo in API key
Rate Limit Errors
Thrown when you exceed the rate limit:
typescript
import { RateLimitError } from '@myxara/sdk-js'
try {
await client.inboxes.list()
} catch (error) {
if (error instanceof RateLimitError) {
console.error('Rate limited!')
console.error('Retry after:', error.retryAfter, 'seconds')
console.error('Limit resets at:', error.resetAt)
// Wait and retry
await new Promise(resolve => setTimeout(resolve, error.retryAfter * 1000))
// Try again
const inboxes = await client.inboxes.list()
}
}Rate Limit Properties
typescript
interface RateLimitError extends APIError {
status: 429
retryAfter: number // Seconds until you can retry
resetAt: Date // When the rate limit resets
limit: number // Your rate limit (e.g., 100)
remaining: number // How many requests you have left (0)
}Automatic Retries
The SDK automatically retries rate-limited requests:
typescript
const client = new MyxaraClient({
apiKey: process.env.MYXARA_API_KEY!,
maxRetries: 5 // Will retry up to 5 times
})
// This will automatically retry if rate limited
await client.inboxes.list()Validation Errors
Thrown when request parameters are invalid:
typescript
import { ValidationError } from '@myxara/sdk-js'
try {
await client.inboxes.create({
local_part: '', // ❌ Invalid - empty
name: 'Support'
})
} catch (error) {
if (error instanceof ValidationError) {
console.error('Validation failed')
console.error('Status:', error.status) // 400
console.error('Errors:', error.errors)
// → { local_part: ['This field is required'] }
// Handle specific field errors
if (error.errors.local_part) {
console.error('local_part errors:', error.errors.local_part)
}
}
}Validation Error Object
typescript
interface ValidationError extends APIError {
status: 400
errors: Record<string, string[]> // Field-specific errors
}Common Validation Errors
typescript
// Empty required field
await client.inboxes.create({
local_part: '', // ❌
name: 'Support'
})
// → { local_part: ['This field is required'] }
// Invalid email format
await client.inboxes.messages(inboxId).send({
to: 'not-an-email', // ❌
subject: 'Test',
text: 'Test'
})
// → { to: ['Invalid email address'] }
// Invalid local_part characters
await client.inboxes.create({
local_part: 'support@123', // ❌ Can't contain @
name: 'Support'
})
// → { local_part: ['Invalid characters in local_part'] }Not Found Errors
Thrown when a resource doesn't exist:
typescript
import { NotFoundError } from '@myxara/sdk-js'
try {
await client.inboxes.get('inbox_nonexistent')
} catch (error) {
if (error instanceof NotFoundError) {
console.error('Inbox not found')
console.error('Status:', error.status) // 404
console.error('Message:', error.message)
// → "Inbox not found"
}
}Conflict Errors
Thrown when a resource already exists:
typescript
try {
// Create inbox
await client.inboxes.create({
local_part: 'support',
name: 'Support Agent'
})
// Try to create again with same local_part
await client.inboxes.create({
local_part: 'support', // ❌ Already exists
name: 'Support Agent 2'
})
} catch (error) {
if (error instanceof APIError && error.status === 409) {
console.error('Inbox with this local_part already exists')
}
}Network Errors
Handle network timeouts and connection issues:
typescript
try {
await client.inboxes.list()
} catch (error) {
if (error instanceof APIError) {
console.error('API error:', error.message)
} else if (error instanceof Error) {
// Network error (fetch failed, timeout, etc.)
console.error('Network error:', error.message)
// Check if timeout
if (error.message.includes('timeout')) {
console.error('Request timed out')
}
// Check if offline
if (error.message.includes('network')) {
console.error('Network connection failed')
}
}
}Custom Timeout
typescript
// Set longer timeout for slow operations
try {
await client.inboxes.list({}, {
timeout: 120000 // 2 minutes
})
} catch (error) {
console.error('Timed out after 2 minutes')
}Handling All Error Types
Comprehensive error handling:
typescript
import {
AuthenticationError,
RateLimitError,
ValidationError,
NotFoundError,
APIError
} from '@myxara/sdk-js'
async function safeCreateInbox(local_part: string, name: string) {
try {
const inbox = await client.inboxes.create({ local_part, name })
return { success: true, inbox }
} catch (error) {
// Authentication error
if (error instanceof AuthenticationError) {
return {
success: false,
error: 'authentication',
message: 'Invalid API key. Please check your credentials.'
}
}
// Rate limit error
if (error instanceof RateLimitError) {
return {
success: false,
error: 'rate_limit',
message: `Too many requests. Retry after ${error.retryAfter} seconds.`,
retryAfter: error.retryAfter
}
}
// Validation error
if (error instanceof ValidationError) {
return {
success: false,
error: 'validation',
message: 'Invalid parameters',
errors: error.errors
}
}
// Not found error
if (error instanceof NotFoundError) {
return {
success: false,
error: 'not_found',
message: 'Resource not found'
}
}
// Conflict error (409)
if (error instanceof APIError && error.status === 409) {
return {
success: false,
error: 'conflict',
message: 'Inbox with this address already exists'
}
}
// Other API errors
if (error instanceof APIError) {
return {
success: false,
error: 'api_error',
message: error.message,
status: error.status
}
}
// Network or unknown errors
return {
success: false,
error: 'unknown',
message: error instanceof Error ? error.message : 'Unknown error'
}
}
}
// Usage
const result = await safeCreateInbox('support', 'Support Agent')
if (result.success) {
console.log('Inbox created:', result.inbox.address)
} else {
console.error('Failed to create inbox:', result.message)
if (result.error === 'validation') {
console.error('Validation errors:', result.errors)
} else if (result.error === 'rate_limit') {
console.log(`Retry after ${result.retryAfter} seconds`)
}
}Retry Logic
Implement custom retry logic:
typescript
async function withRetry<T>(
fn: () => Promise<T>,
maxAttempts = 3,
delayMs = 1000
): Promise<T> {
let lastError: any
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn()
} catch (error) {
lastError = error
// Don't retry validation or authentication errors
if (error instanceof ValidationError || error instanceof AuthenticationError) {
throw error
}
// For rate limits, use their retry-after
if (error instanceof RateLimitError) {
const delay = error.retryAfter * 1000
console.log(`Rate limited. Waiting ${error.retryAfter}s...`)
await new Promise(resolve => setTimeout(resolve, delay))
continue
}
// Don't retry on last attempt
if (attempt === maxAttempts) {
break
}
// Exponential backoff for other errors
const delay = delayMs * Math.pow(2, attempt - 1)
console.log(`Attempt ${attempt} failed. Retrying in ${delay}ms...`)
await new Promise(resolve => setTimeout(resolve, delay))
}
}
throw lastError
}
// Usage
const inbox = await withRetry(
() => client.inboxes.create({
local_part: 'support',
name: 'Support Agent'
}),
maxAttempts: 5,
delayMs: 1000
)Logging Errors
Production-ready error logging:
typescript
import { APIError } from '@myxara/sdk-js'
function logError(error: any, context?: Record<string, any>) {
const timestamp = new Date().toISOString()
if (error instanceof APIError) {
console.error(JSON.stringify({
timestamp,
type: 'api_error',
status: error.status,
message: error.message,
context,
// Add request ID if available
request_id: error.headers?.['x-request-id']
}))
} else if (error instanceof Error) {
console.error(JSON.stringify({
timestamp,
type: 'error',
message: error.message,
stack: error.stack,
context
}))
} else {
console.error(JSON.stringify({
timestamp,
type: 'unknown',
error: String(error),
context
}))
}
}
// Usage
try {
await client.inboxes.create({
local_part: 'support',
name: 'Support'
})
} catch (error) {
logError(error, {
operation: 'create_inbox',
local_part: 'support'
})
throw error
}Complete Example
typescript
import {
MyxaraClient,
AuthenticationError,
RateLimitError,
ValidationError,
NotFoundError,
APIError
} from '@myxara/sdk-js'
const client = new MyxaraClient({
apiKey: process.env.MYXARA_API_KEY!,
maxRetries: 3 // Automatic retries
})
async function sendEmail(inboxId: string, to: string, subject: string, text: string) {
try {
const message = await client.inboxes.messages(inboxId).send({
to,
subject,
text
})
console.log(`✅ Email sent: ${message.id}`)
return message
} catch (error) {
// Handle specific errors
if (error instanceof AuthenticationError) {
console.error('❌ Authentication failed - check API key')
// Maybe refresh API key or alert admin
} else if (error instanceof RateLimitError) {
console.error(`⏸️ Rate limited - retry after ${error.retryAfter}s`)
// Queue for later or implement backoff
} else if (error instanceof ValidationError) {
console.error('❌ Invalid email parameters:')
for (const [field, errors] of Object.entries(error.errors)) {
console.error(` ${field}: ${errors.join(', ')}`)
}
// Maybe validate inputs before sending
} else if (error instanceof NotFoundError) {
console.error('❌ Inbox not found')
// Maybe create inbox first
} else if (error instanceof APIError) {
console.error(`❌ API error (${error.status}): ${error.message}`)
// Log to error tracking service
} else {
console.error('❌ Unexpected error:', error)
// Log to error tracking service
}
throw error
}
}
// Usage
sendEmail(
'inbox_abc123',
'customer@example.com',
'Welcome!',
'Thanks for signing up.'
).catch(error => {
console.error('Failed to send email')
process.exit(1)
})TypeScript Types
typescript
import type {
APIError,
AuthenticationError,
RateLimitError,
ValidationError,
NotFoundError
} from '@myxara/sdk-js'
function handleError(error: unknown) {
if (error instanceof ValidationError) {
// TypeScript knows about error.errors
const fieldErrors: Record<string, string[]> = error.errors
} else if (error instanceof RateLimitError) {
// TypeScript knows about error.retryAfter
const retryAfter: number = error.retryAfter
const resetAt: Date = error.resetAt
} else if (error instanceof APIError) {
// TypeScript knows about error.status
const status: number = error.status
}
}Next Steps
- Client → - Configure retries and timeouts
- Examples → - See error handling in action
- Authentication → - Learn about API keys