Error Handling
This guide covers best practices for handling errors in your TraderPal Connect integration.
Error Response Format
All API errors follow a consistent format:
{
  "error": {
    "code": "invalid_request",
    "message": "The request was invalid",
    "details": {
      "field": "symbol",
      "reason": "Invalid stock symbol"
    },
    "requestId": "req_123456789"
  }
}
Common Error Codes
Authentication Errors (4xx)
| Code | Description | Resolution | 
|---|---|---|
| 401 | Unauthorized | Check API credentials | 
| 403 | Forbidden | Verify permissions | 
| 404 | Not Found | Check resource exists | 
| 429 | Too Many Requests | Implement rate limiting | 
Business Logic Errors (4xx)
| Code | Description | Resolution | 
|---|---|---|
| 400 | Invalid Request | Validate input data | 
| 422 | Unprocessable Entity | Check business rules | 
| 409 | Conflict | Handle race conditions | 
| 412 | Precondition Failed | Check state requirements | 
Server Errors (5xx)
| Code | Description | Resolution | 
|---|---|---|
| 500 | Internal Server Error | Retry with backoff | 
| 502 | Bad Gateway | Check service status | 
| 503 | Service Unavailable | Implement circuit breaker | 
| 504 | Gateway Timeout | Adjust timeout settings | 
Error Handling Strategies
Retry Logic
async function retryRequest(fn, maxRetries = 3, delay = 1000) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (!isRetryableError(error) || i === maxRetries - 1) {
        throw error;
      }
      await sleep(delay * Math.pow(2, i));
    }
  }
}
function isRetryableError(error) {
  return [500, 502, 503, 504].includes(error.status);
}
Circuit Breaker
class CircuitBreaker {
  constructor(fn, options = {}) {
    this.fn = fn;
    this.state = 'closed';
    this.failureCount = 0;
    this.failureThreshold = options.failureThreshold || 5;
    this.resetTimeout = options.resetTimeout || 60000;
  }
  async execute(...args) {
    if (this.state === 'open') {
      throw new Error('Circuit breaker is open');
    }
    try {
      const result = await this.fn(...args);
      this.failureCount = 0;
      return result;
    } catch (error) {
      this.failureCount++;
      if (this.failureCount >= this.failureThreshold) {
        this.state = 'open';
        setTimeout(() => this.reset(), this.resetTimeout);
      }
      throw error;
    }
  }
  reset() {
    this.state = 'closed';
    this.failureCount = 0;
  }
}
Rate Limiting
class RateLimiter {
  constructor(limit, interval) {
    this.limit = limit;
    this.interval = interval;
    this.requests = [];
  }
  async execute(fn) {
    this.clearOldRequests();
    if (this.requests.length >= this.limit) {
      throw new Error('Rate limit exceeded');
    }
    this.requests.push(Date.now());
    return fn();
  }
  clearOldRequests() {
    const now = Date.now();
    this.requests = this.requests.filter(
      time => now - time < this.interval
    );
  }
}
Error Handling Examples
Order Placement
async function placeOrder(orderData) {
  const circuitBreaker = new CircuitBreaker(
    client.orders.create,
    { failureThreshold: 3 }
  );
  try {
    const order = await retryRequest(
      () => circuitBreaker.execute(orderData)
    );
    return order;
  } catch (error) {
    if (error.code === 'insufficient_funds') {
      // Handle business logic error
      throw new BusinessError('Insufficient funds for order');
    } else if (error.status === 429) {
      // Handle rate limiting
      await sleep(error.retryAfter * 1000);
      return placeOrder(orderData);
    } else {
      // Handle unexpected errors
      logError(error);
      throw error;
    }
  }
}
User Authentication
async function authenticateUser(credentials) {
  try {
    const auth = await client.auth.login(credentials);
    return auth;
  } catch (error) {
    switch (error.code) {
      case 'invalid_credentials':
        throw new AuthError('Invalid username or password');
      case 'account_locked':
        throw new AuthError('Account locked. Please contact support');
      case 'requires_2fa':
        return handle2FAFlow(credentials);
      default:
        logError(error);
        throw new Error('Authentication failed');
    }
  }
}
Logging Best Practices
Error Log Format
function logError(error, context = {}) {
  const errorLog = {
    timestamp: new Date().toISOString(),
    requestId: error.requestId,
    code: error.code,
    message: error.message,
    stack: error.stack,
    context: {
      userId: context.userId,
      action: context.action,
      ...context
    }
  };
  logger.error(errorLog);
}
Sensitive Data Handling
function sanitizeError(error) {
  const sensitiveFields = ['password', 'token', 'key'];
  const sanitized = { ...error };
  sensitiveFields.forEach(field => {
    if (sanitized[field]) {
      sanitized[field] = '[REDACTED]';
    }
  });
  return sanitized;
}
Monitoring and Alerts
Error Rate Monitoring
class ErrorMonitor {
  constructor(threshold = 0.05) {
    this.errors = [];
    this.requests = 0;
    this.threshold = threshold;
  }
  trackRequest() {
    this.requests++;
    this.checkErrorRate();
  }
  trackError(error) {
    this.errors.push({
      timestamp: Date.now(),
      error
    });
    this.checkErrorRate();
  }
  checkErrorRate() {
    const errorRate = this.errors.length / this.requests;
    if (errorRate > this.threshold) {
      alertTeam('High error rate detected');
    }
  }
}
Best Practices
- 
Validate Input Data
- Check required fields
 - Validate data types
 - Sanitize user input
 
 - 
Handle Edge Cases
- Network timeouts
 - Service unavailability
 - Race conditions
 
 - 
Implement Fallbacks
- Cache responses
 - Default values
 - Graceful degradation
 
 - 
Monitor and Alert
- Track error rates
 - Set up alerts
 - Monitor response times