Error Handling

The Tenzro Platform SDK provides typed errors for all failure cases, making it easy to handle errors gracefully in your application.

Error Types

All SDK errors extend the base TenzroError class:

import {
  TenzroError,
  AuthenticationError,
  AuthorizationError,
  ValidationError,
  NotFoundError,
  RateLimitError,
  InternalError,
  NetworkError,
} from '@tenzro/platform';

Error Hierarchy

Error ClassHTTP StatusDescription
AuthenticationError401Invalid or missing API key
AuthorizationError403Insufficient permissions
ValidationError400Invalid request parameters
NotFoundError404Resource not found
RateLimitError429Rate limit exceeded
InternalError500+Server-side error
NetworkError-Connection failed

Basic Error Handling

try {
  const wallet = await platform.wallet.create({
    name: 'Treasury',
    type: 'multi-sig',
    chain: 'ethereum',
  });
} catch (error) {
  if (error instanceof TenzroError) {
    console.error('API Error:', error.message);
    console.error('Error Code:', error.code);
    console.error('Request ID:', error.requestId);
  } else {
    throw error;
  }
}

Handling Specific Errors

import {
  TenzroError,
  AuthenticationError,
  RateLimitError,
  ValidationError,
} from '@tenzro/platform';

try {
  await platform.wallet.create({ ... });
} catch (error) {
  if (error instanceof AuthenticationError) {
    // Invalid API key - check configuration
    console.error('Authentication failed:', error.message);
    // Redirect to auth or refresh token

  } else if (error instanceof RateLimitError) {
    // Rate limited - wait and retry
    console.log(`Rate limited. Retry after ${error.retryAfter}s`);
    await sleep(error.retryAfter * 1000);
    // Retry the request

  } else if (error instanceof ValidationError) {
    // Invalid request - check parameters
    console.error('Validation errors:', error.errors);
    // error.errors is an array of field-level errors
    for (const fieldError of error.errors) {
      console.error(`  ${fieldError.field}: ${fieldError.message}`);
    }

  } else if (error instanceof TenzroError) {
    // Other API error
    console.error('API error:', error.code, error.message);

  } else {
    throw error;
  }
}

Error Properties

All TenzroError instances have these properties:

interface TenzroError extends Error {
  // Standard error message
  message: string;

  // Machine-readable error code
  code: string;

  // HTTP status code
  status: number;

  // Unique request identifier for support
  requestId: string;

  // Original response (if available)
  response?: Response;

  // Retry information (for rate limits)
  retryAfter?: number;

  // Field-level validation errors
  errors?: Array<{
    field: string;
    message: string;
    code: string;
  }>;
}

Validation Errors

ValidationError includes detailed field-level errors:

try {
  await platform.wallet.create({
    name: '',  // Invalid: empty name
    type: 'invalid-type',  // Invalid: unknown type
    chain: 'ethereum',
  });
} catch (error) {
  if (error instanceof ValidationError) {
    // error.errors contains:
    // [
    //   { field: 'name', message: 'Name is required', code: 'required' },
    //   { field: 'type', message: 'Invalid wallet type', code: 'invalid_enum' }
    // ]

    for (const err of error.errors) {
      console.error(`${err.field}: ${err.message}`);
    }
  }
}

Rate Limiting

Handle rate limits with exponential backoff:

async function withRetry<T>(
  fn: () => Promise<T>,
  maxRetries = 3
): Promise<T> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      if (error instanceof RateLimitError && attempt < maxRetries - 1) {
        const delay = error.retryAfter
          ? error.retryAfter * 1000
          : Math.pow(2, attempt) * 1000;

        console.log(`Rate limited, retrying in ${delay}ms...`);
        await new Promise(r => setTimeout(r, delay));
        continue;
      }
      throw error;
    }
  }
  throw new Error('Max retries exceeded');
}

// Usage
const wallet = await withRetry(() =>
  platform.wallet.create({ name: 'Treasury', type: 'eoa', chain: 'ethereum' })
);

Network Errors

Handle connection failures separately:

import { NetworkError } from '@tenzro/platform';

try {
  await platform.wallet.list();
} catch (error) {
  if (error instanceof NetworkError) {
    console.error('Connection failed:', error.message);
    console.error('Is offline?', !navigator.onLine);
    // Show offline UI or retry later
  }
}

Global Error Handler

Set up a global error handler for consistent error processing:

import { TenzroError, RateLimitError } from '@tenzro/platform';

function handleTenzroError(error: unknown): never {
  if (error instanceof RateLimitError) {
    // Log and potentially queue for retry
    logger.warn('Rate limited', {
      requestId: error.requestId,
      retryAfter: error.retryAfter,
    });
  } else if (error instanceof TenzroError) {
    // Log API errors
    logger.error('Tenzro API error', {
      code: error.code,
      message: error.message,
      requestId: error.requestId,
      status: error.status,
    });
  }

  throw error;
}

// Usage with wrapper
async function safeApiCall<T>(fn: () => Promise<T>): Promise<T> {
  try {
    return await fn();
  } catch (error) {
    handleTenzroError(error);
  }
}