Skip to main content

RebelfiError Class

All API errors are thrown as RebelfiError instances with structured information:
import { RebelfiError, ErrorCode } from '@rebelfi/sdk';

try {
  await client.operations.supply(request);
} catch (error) {
  if (error instanceof RebelfiError) {
    console.error('Message:', error.message);
    console.error('Status:', error.statusCode);
    console.error('Code:', error.code);
    console.error('Details:', error.details);
  }
}

Properties

PropertyTypeDescription
messagestringHuman-readable error message
statusCodenumberHTTP status code
codeErrorCodeMachine-readable error code
detailsobjectAdditional error context

Checking Error Type

Use the .is() method to check for specific errors:
if (error instanceof RebelfiError) {
  if (error.is(ErrorCode.INSUFFICIENT_BALANCE)) {
    // Show "insufficient funds" message to user
  } else if (error.is(ErrorCode.OPERATION_EXPIRED)) {
    // Retry with a new operation
  }
}

Error Codes

Validation Errors (4xx)

CodeDescriptionRecommended Action
INVALID_AMOUNTAmount is zero, negative, or malformedValidate amount before calling
INVALID_ADDRESSWallet address format is invalidValidate address format
INVALID_TOKENToken address not recognizedUse address from strategy
if (error.is(ErrorCode.INVALID_AMOUNT)) {
  // Show validation error to user
  showError('Please enter a valid amount');
}

Business Logic Errors (4xx)

CodeDescriptionRecommended Action
INSUFFICIENT_BALANCEWallet balance too low for operationShow balance, suggest lower amount
STRATEGY_NOT_ACTIVEStrategy is paused or deprecatedRefresh venues, pick another
ALLOCATION_NOT_FOUNDNo position exists at this venueCheck allocations first
OPERATION_EXPIREDUnsigned transaction expiredCreate new operation
OPERATION_ALREADY_SUBMITTEDTransaction already submittedCheck operation status
TOKEN_MISMATCHToken doesn’t match strategyUse tokenAddress from strategy
INVALID_OPERATION_STATUSOperation in wrong state for actionCheck operation status first
OPERATION_IN_PROGRESSAnother operation is executing for this walletWait for it to complete, or cancel it
switch (error.code) {
  case ErrorCode.INSUFFICIENT_BALANCE:
    const balance = error.details?.available;
    showError(`Insufficient balance. Available: ${balance}`);
    break;

  case ErrorCode.STRATEGY_NOT_ACTIVE:
    // Refresh and show available strategies
    await refreshStrategies();
    showError('This strategy is no longer available');
    break;

  case ErrorCode.OPERATION_EXPIRED:
    // Automatically retry
    return await retryOperation();

  case ErrorCode.OPERATION_IN_PROGRESS:
    // Another operation is executing — wait or cancel it
    const { operationId, walletId } = error.details as { operationId: number; walletId: number };
    showError(`Operation ${operationId} is still executing. Please wait for it to complete.`);
    break;
}

Resource Errors (404)

CodeDescriptionRecommended Action
VENUE_NOT_FOUNDVenue ID doesn’t existRefresh venue list
STRATEGY_NOT_FOUNDStrategy ID doesn’t existRefresh venue list
OPERATION_NOT_FOUNDOperation ID doesn’t existMay have been cleaned up
TRANSACTION_NOT_FOUNDTransaction ID doesn’t existCheck operation status
WALLET_NOT_FOUNDWallet not registeredRegister the wallet first via wallets.register()
ORGANIZATION_NOT_FOUNDAPI key’s org not foundCheck API key
TOKEN_NOT_FOUNDToken not supportedCheck supported tokens

Simulation Errors (4xx)

CodeDescriptionRecommended Action
INSUFFICIENT_GASNot enough SOL for transaction feePrompt user to add SOL
SIMULATION_FAILEDTransaction simulation failedCheck error details
if (error.is(ErrorCode.INSUFFICIENT_GAS)) {
  showError('Please add SOL to cover transaction fees');
}

Authentication Errors (401/403)

CodeDescriptionRecommended Action
INVALID_API_KEYAPI key not recognizedCheck API key configuration
API_KEY_DISABLEDAPI key has been revokedContact support

Rate Limiting (429)

CodeDescriptionRecommended Action
RATE_LIMIT_EXCEEDEDToo many requestsImplement backoff
if (error.is(ErrorCode.RATE_LIMIT_EXCEEDED)) {
  // Exponential backoff
  await delay(retryCount * 1000);
  return await retry();
}

Network Errors

CodeDescriptionRecommended Action
TIMEOUTRequest timed outRetry with backoff
NETWORK_ERRORNetwork connectivity issueCheck connection, retry
UNKNOWN_ERRORUnexpected errorLog and report

Error Details by Code

Many errors include a details object with structured context. Here are the fields returned for each error code:
Error CodeDetails FieldsExample
INSUFFICIENT_BALANCErequested: string, available: string{ "requested": "1000000", "available": "500000" }
OPERATION_IN_PROGRESSoperationId: number, walletId: number{ "operationId": 123, "walletId": 45 }
INSUFFICIENT_GASwalletAddress: string, blockchain: string{ "walletAddress": "So11...abc", "blockchain": "solana" }
SIMULATION_FAILEDlogs?: string[], unitsConsumed?: number{ "logs": ["Program log: Error"], "unitsConsumed": 50000 }
TOKEN_MISMATCHexpected: string, actual: string{ "expected": "USDC", "actual": "USDT" }
STRATEGY_NOT_ACTIVEstrategyId: number{ "strategyId": 1 }
ALLOCATION_NOT_FOUNDstrategyId: number, walletAddress: string{ "strategyId": 1, "walletAddress": "So11...abc" }

Transaction Failure Codes

When a transaction fails, check the failureCode for details:
const operation = await client.operations.get(operationId);

if (operation.status === 'failed') {
  const tx = operation.transactions[0];

  switch (tx.failureCode) {
    case 'REVERTED':
      console.error('Contract reverted:', tx.revertReason);
      break;
    case 'OUT_OF_GAS':
      console.error('Transaction ran out of gas');
      break;
    case 'TIMEOUT':
      console.error('Transaction not confirmed in time');
      break;
    case 'INSUFFICIENT_FUNDS':
      console.error('Not enough SOL for gas');
      break;
  }
}
CodeDescription
REVERTEDSmart contract execution reverted
OUT_OF_GASTransaction ran out of gas
TIMEOUTNot included in block within timeout
NONCE_TOO_LOWNonce already used (duplicate tx)
INSUFFICIENT_FUNDSNot enough native token for gas
REPLACEDTransaction replaced by another
DROPPEDDropped from mempool
UNKNOWNUnknown failure reason

Error Handling Patterns

Comprehensive Handler

import { RebelfiError, ErrorCode } from '@rebelfi/sdk';

async function handleSupply(params: SupplyParams) {
  try {
    const operation = await client.operations.supply(params);
    return { success: true, operation };
  } catch (error) {
    if (!(error instanceof RebelfiError)) {
      // Unexpected error
      console.error('Unexpected error:', error);
      return { success: false, error: 'An unexpected error occurred' };
    }

    // User-fixable errors
    if (error.is(ErrorCode.INSUFFICIENT_BALANCE)) {
      return {
        success: false,
        error: 'Insufficient balance',
        userAction: 'deposit_more'
      };
    }

    if (error.is(ErrorCode.INSUFFICIENT_GAS)) {
      return {
        success: false,
        error: 'Need SOL for transaction fee',
        userAction: 'add_sol'
      };
    }

    // Retryable errors
    if (error.is(ErrorCode.RATE_LIMIT_EXCEEDED) ||
        error.is(ErrorCode.TIMEOUT) ||
        error.is(ErrorCode.NETWORK_ERROR)) {
      return {
        success: false,
        error: 'Temporary error',
        retryable: true
      };
    }

    // Strategy issues
    if (error.is(ErrorCode.STRATEGY_NOT_ACTIVE) ||
        error.is(ErrorCode.STRATEGY_NOT_FOUND)) {
      return {
        success: false,
        error: 'Strategy unavailable',
        userAction: 'select_different_strategy'
      };
    }

    // Auth issues
    if (error.is(ErrorCode.INVALID_API_KEY) ||
        error.is(ErrorCode.API_KEY_DISABLED)) {
      console.error('API key issue:', error.message);
      return {
        success: false,
        error: 'Service configuration error'
      };
    }

    // Unknown API error
    return {
      success: false,
      error: error.message
    };
  }
}

Retry with Backoff

async function withRetry<T>(
  fn: () => Promise<T>,
  options: { maxAttempts?: number; baseDelay?: number } = {}
): Promise<T> {
  const { maxAttempts = 3, baseDelay = 1000 } = options;

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (error) {
      if (!(error instanceof RebelfiError)) throw error;

      const isRetryable =
        error.is(ErrorCode.TIMEOUT) ||
        error.is(ErrorCode.NETWORK_ERROR) ||
        error.is(ErrorCode.RATE_LIMIT_EXCEEDED);

      if (!isRetryable || attempt === maxAttempts) {
        throw error;
      }

      const delay = baseDelay * Math.pow(2, attempt - 1);
      await new Promise(r => setTimeout(r, delay));
    }
  }

  throw new Error('Max attempts reached');
}

// Usage
const operation = await withRetry(() =>
  client.operations.supply(params)
);

Operation Expiry Handling

async function supplyWithRetry(params: SupplyParams) {
  const maxRetries = 2;

  for (let i = 0; i < maxRetries; i++) {
    try {
      const operation = await client.operations.supply(params);

      // Check if we have enough time
      const expiresAt = new Date(operation.expiresAt);
      const timeLeft = expiresAt.getTime() - Date.now();

      if (timeLeft < 30000) {
        console.warn('Operation expires soon, may need retry');
      }

      return operation;
    } catch (error) {
      if (error instanceof RebelfiError &&
          error.is(ErrorCode.OPERATION_EXPIRED)) {
        console.log('Operation expired, retrying...');
        continue;
      }
      throw error;
    }
  }

  throw new Error('Failed after retries');
}

Next Steps