Skip to main content

Errors

The SDK provides typed error classes for precise error handling.

Error Hierarchy

Error
└── BorrowSDKError (base class)
    ├── WalletNotConnectedError
    ├── SmartAccountError
    ├── ApiError
    ├── ConfigValidationError
    ├── QuoteError
    └── WorkflowError

BorrowSDKError

Base error class for all SDK errors.
class BorrowSDKError extends Error {
  public readonly code: ErrorCode;
  public readonly context?: Record<string, any>;

  constructor(
    message: string,
    code?: ErrorCode,
    context?: Record<string, any>
  );

  toJSON(): object;
}

Properties

PropertyTypeDescription
codeErrorCodeError classification
contextobjectAdditional error context
messagestringError message

Example

try {
  await sdk.getLoan({ ... });
} catch (error) {
  if (error instanceof BorrowSDKError) {
    console.log('Code:', error.code);
    console.log('Message:', error.message);
    console.log('Context:', error.context);
    console.log('JSON:', error.toJSON());
  }
}

WalletNotConnectedError

Thrown when a wallet operation is attempted without a connected wallet.
class WalletNotConnectedError extends BorrowSDKError {
  constructor(message?: string);
}

Default Code

ErrorCode.WALLET_NOT_CONNECTED

Common Causes

  • Calling methods before wallet is connected
  • Wallet disconnected during operation
  • Missing wallet provider in config

Example

try {
  await sdk.setup();
} catch (error) {
  if (error instanceof WalletNotConnectedError) {
    console.error('Please connect your wallet first');
    showConnectWalletModal();
  }
}

SmartAccountError

Thrown when smart account operations fail.
class SmartAccountError extends BorrowSDKError {
  constructor(message: string, cause?: unknown);
}

Default Code

ErrorCode.SMART_ACCOUNT_ERROR

Common Causes

  • Signature verification failed
  • Smart account derivation failed
  • Session authorization failed
  • Account not initialized

Example

try {
  await sdk.startNewLoan();
} catch (error) {
  if (error instanceof SmartAccountError) {
    console.error('Smart account error:', error.message);

    // Check if it's a session issue
    if (error.message.includes('session')) {
      await sdk.setup(); // Re-initialize session
    }
  }
}

ApiError

Thrown when API requests fail.
class ApiError extends BorrowSDKError {
  public readonly statusCode?: number;

  constructor(
    message: string,
    statusCode?: number,
    context?: Record<string, any>
  );

  static fromResponse(
    statusCode: number,
    message?: string,
    body?: any
  ): ApiError;
}

Default Code

ErrorCode.API_ERROR

Properties

PropertyTypeDescription
statusCodenumberHTTP status code

Common Status Codes

CodeMeaning
400Bad request / validation error
401Unauthorized / invalid API key
403Forbidden
404Resource not found
429Rate limited
500Server error

Example

try {
  await sdk.getQuotes({ ... });
} catch (error) {
  if (error instanceof ApiError) {
    switch (error.statusCode) {
      case 401:
        console.error('Invalid API key');
        break;
      case 429:
        console.error('Rate limited. Please wait.');
        await delay(5000);
        // Retry
        break;
      case 500:
        console.error('Server error. Please try again later.');
        break;
      default:
        console.error('API error:', error.message);
    }
  }
}

ConfigValidationError

Thrown when SDK configuration is invalid.
class ConfigValidationError extends BorrowSDKError {
  constructor(message: string);
}

Default Code

ErrorCode.CONFIG_ERROR

Common Causes

  • Missing required config options
  • Invalid config values
  • Invalid URL format
  • Invalid chain type

Example

try {
  const sdk = new BorrowSDK({
    apiKey: '', // Empty - will throw
    baseUrl: 'not-a-url', // Invalid - will throw
    chain: 'invalid' as any, // Invalid - will throw
    wallet: { address: 'bc1...' } // Missing signMessage - will throw
  });
} catch (error) {
  if (error instanceof ConfigValidationError) {
    console.error('Configuration error:', error.message);
    // e.g., "apiKey is required and must be a non-empty string"
  }
}

Validation Rules

OptionValidation
apiKeyNon-empty string
baseUrlValid URL
chainValid ChainType
wallet.addressNon-empty string
wallet.signMessageFunction
workflowPollInterval>= 100
sessionValiditySeconds>= 60

QuoteError

Thrown when quote operations fail.
class QuoteError extends BorrowSDKError {
  constructor(message: string, context?: Record<string, any>);
}

Default Code

ErrorCode.QUOTE_ERROR

Common Causes

  • No quotes available for parameters
  • Invalid quote parameters
  • Quote expired

Example

try {
  await sdk.getLoan({
    collateralBTC: 0.001, // Too small
    loanAmountUSD: 100000 // Too large
  });
} catch (error) {
  if (error instanceof QuoteError) {
    console.error('No quotes available:', error.message);
    showMessage('Please adjust your loan parameters');
  }
}

WorkflowError

Thrown when workflow operations fail.
class WorkflowError extends BorrowSDKError {
  public readonly workflowId?: string;

  constructor(
    message: string,
    workflowId?: string,
    context?: Record<string, any>
  );
}

Default Code

ErrorCode.WORKFLOW_ERROR

Properties

PropertyTypeDescription
workflowIdstringFailed workflow ID

Common Causes

  • Workflow timeout
  • Deposit not received
  • Bridge failure
  • Execution failure

Example

try {
  await sdk.trackWorkflow(workflowId, callbacks);
} catch (error) {
  if (error instanceof WorkflowError) {
    console.error('Workflow failed:', error.message);
    console.error('Workflow ID:', error.workflowId);

    // Check status
    const status = await sdk.getStatus(error.workflowId!);
    console.log('Final status:', status);
  }
}

Error Handling Patterns

Comprehensive Handler

async function handleSDKOperation<T>(
  operation: () => Promise<T>
): Promise<T | null> {
  try {
    return await operation();
  } catch (error) {
    if (error instanceof WalletNotConnectedError) {
      showModal('Please connect your wallet');
      return null;
    }

    if (error instanceof SmartAccountError) {
      if (error.message.includes('session')) {
        // Try to refresh session
        await sdk.setup();
        return await operation(); // Retry
      }
      showError('Wallet error: ' + error.message);
      return null;
    }

    if (error instanceof ApiError) {
      if (error.statusCode === 429) {
        showError('Too many requests. Please wait.');
        await delay(5000);
        return await operation(); // Retry
      }
      showError('Server error: ' + error.message);
      return null;
    }

    if (error instanceof ConfigValidationError) {
      console.error('Config error:', error.message);
      throw error; // Fatal - can't recover
    }

    if (error instanceof QuoteError) {
      showError('No quotes available. Try different parameters.');
      return null;
    }

    if (error instanceof WorkflowError) {
      showError('Operation failed: ' + error.message);
      // Log for debugging
      console.error('Workflow ID:', error.workflowId);
      return null;
    }

    // Unknown error
    console.error('Unexpected error:', error);
    showError('An unexpected error occurred');
    return null;
  }
}

Type Guard

function isBorrowSDKError(error: unknown): error is BorrowSDKError {
  return error instanceof BorrowSDKError;
}

// Usage
if (isBorrowSDKError(error)) {
  console.log('SDK Error:', error.code, error.message);
}

Error Logging

function logError(error: BorrowSDKError) {
  const errorData = {
    code: error.code,
    message: error.message,
    context: error.context,
    stack: error.stack,
    timestamp: new Date().toISOString()
  };

  // Send to logging service
  analytics.trackError(errorData);

  // Log locally
  console.error('SDK Error:', JSON.stringify(errorData, null, 2));
}

ErrorCode Reference

enum ErrorCode {
  WALLET_NOT_CONNECTED = 'WALLET_NOT_CONNECTED',
  SMART_ACCOUNT_ERROR = 'SMART_ACCOUNT_ERROR',
  API_ERROR = 'API_ERROR',
  CONFIG_ERROR = 'CONFIG_ERROR',
  QUOTE_ERROR = 'QUOTE_ERROR',
  WORKFLOW_ERROR = 'WORKFLOW_ERROR',
  STORAGE_ERROR = 'STORAGE_ERROR',
  NETWORK_ERROR = 'NETWORK_ERROR',
  VALIDATION_ERROR = 'VALIDATION_ERROR'
}

Usage

import { ErrorCode, BorrowSDKError } from '@satsterminal-sdk/borrow';

if (error instanceof BorrowSDKError) {
  switch (error.code) {
    case ErrorCode.WALLET_NOT_CONNECTED:
      // Handle wallet not connected
      break;
    case ErrorCode.API_ERROR:
      // Handle API error
      break;
    // ... etc
  }
}