Skip to content

Error Handling ​

Learn how to handle errors gracefully when using the Kitbase SDK.

Overview ​

The TypeScript SDKs provide typed error classes that allow you to handle specific error conditions precisely. This enables you to provide better user experiences and implement robust retry logic.

Error Types ​

Events Errors ​

ErrorHTTP StatusDescription
AuthenticationError401Invalid or missing API key
ValidationError400/422Missing or invalid required fields
TimeoutError-Request exceeded timeout (30s)
ApiError4xx/5xxAPI returned an error response

TypeScript ​

Events Error Handling ​

typescript
import {
  init,
  KitbaseError,
  AuthenticationError,
  ApiError,
  ValidationError,
  TimeoutError,
} from '@kitbase/analytics';

const kitbase = init({ sdkKey: '<YOUR_API_KEY>' });

try {
  await kitbase.track({
    channel: 'payments',
    event: 'New Subscription',
  });
} catch (error) {
  if (error instanceof AuthenticationError) {
    // Invalid API key - check your sdkKey
    console.error('Authentication failed');
  } else if (error instanceof ValidationError) {
    // Missing required fields
    console.error(`Validation error: ${error.field}`);
  } else if (error instanceof TimeoutError) {
    // Request timed out - retry later
    console.error('Request timed out');
  } else if (error instanceof ApiError) {
    // API returned an error
    console.error(`API error: ${error.statusCode}`);
    console.error(error.response);
  } else if (error instanceof KitbaseError) {
    // Generic SDK error
    console.error(error.message);
  }
}

Retry with Exponential Backoff ​

typescript
import type { TrackOptions, TrackResponse } from '@kitbase/analytics';
import { TimeoutError, ApiError } from '@kitbase/analytics';

async function trackWithRetry(
  kitbase: Kitbase,
  options: TrackOptions,
  retries = 3
): Promise<TrackResponse> {
  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      return await kitbase.track(options);
    } catch (error) {
      // Don't retry auth or validation errors
      if (error instanceof AuthenticationError) throw error;
      if (error instanceof ValidationError) throw error;

      // Retry on timeout or server errors
      const shouldRetry =
        error instanceof TimeoutError ||
        (error instanceof ApiError && error.statusCode >= 500);

      if (shouldRetry && attempt < retries) {
        const delay = Math.pow(2, attempt) * 1000;
        await new Promise((resolve) => setTimeout(resolve, delay));
        continue;
      }

      throw error;
    }
  }
  throw new Error('Max retries exceeded');
}

Error Properties ​

TypeScript ​

AuthenticationError ​

typescript
interface AuthenticationError extends KitbaseError {
  message: string; // "Invalid or missing API key"
}

ValidationError ​

typescript
interface ValidationError extends KitbaseError {
  message: string; // Error description
  field: string;   // The field that failed validation
}

TimeoutError ​

typescript
interface TimeoutError extends KitbaseError {
  message: string; // "Request timed out"
}

ApiError ​

typescript
interface ApiError extends KitbaseError {
  message: string;      // Error description from API
  statusCode: number;   // HTTP status code
  response: unknown;    // Raw response body
}

Error message language ​

The API writes message in the language of the request's Accept-Language header — English, or Arabic for ar (browsers send this header on their own, so a visitor with an Arabic browser gets Arabic messages). A message with no Arabic translation stays English. The error code never changes with the language: always branch on the code or the error class, never on the message text.

Best Practices ​

1. Don't Retry Authentication Errors ​

Authentication errors indicate a configuration problem. Log these prominently and don't retry:

typescript
if (error instanceof AuthenticationError) {
  logger.error('Kitbase authentication failed - check API key');
  notifyOps('Kitbase API key is invalid');
  throw error; // Don't retry
}

2. Implement Exponential Backoff ​

For transient errors (timeouts, server errors), use exponential backoff:

typescript
const delay = Math.min(Math.pow(2, attempt) * 1000, 30000); // Max 30s
await new Promise(resolve => setTimeout(resolve, delay));

3. Log Errors for Debugging ​

Include context when logging errors:

typescript
} catch (error) {
  logger.error('Failed to track event', {
    channel: options.channel,
    event: options.event,
    error: error instanceof KitbaseError ? {
      type: error.constructor.name,
      message: error.message,
    } : error,
  });
}

4. Graceful Degradation ​

Don't let tracking failures break your application:

typescript
async function safeTrack(options: TrackOptions) {
  try {
    await kitbase.track(options);
  } catch (error) {
    // Log but don't throw - tracking is non-critical
    console.error('Event tracking failed:', error);
  }
}

5. Validate Before Sending ​

Catch validation errors early:

typescript
function validateTrackOptions(options: TrackOptions): void {
  if (!options.channel?.trim()) {
    throw new Error('Channel is required');
  }
  if (!options.event?.trim()) {
    throw new Error('Event is required');
  }
}

Next steps ​

Released under the MIT License.