Skip to main content

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)

CodeDescriptionResolution
401UnauthorizedCheck API credentials
403ForbiddenVerify permissions
404Not FoundCheck resource exists
429Too Many RequestsImplement rate limiting

Business Logic Errors (4xx)

CodeDescriptionResolution
400Invalid RequestValidate input data
422Unprocessable EntityCheck business rules
409ConflictHandle race conditions
412Precondition FailedCheck state requirements

Server Errors (5xx)

CodeDescriptionResolution
500Internal Server ErrorRetry with backoff
502Bad GatewayCheck service status
503Service UnavailableImplement circuit breaker
504Gateway TimeoutAdjust 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

  1. Validate Input Data

    • Check required fields
    • Validate data types
    • Sanitize user input
  2. Handle Edge Cases

    • Network timeouts
    • Service unavailability
    • Race conditions
  3. Implement Fallbacks

    • Cache responses
    • Default values
    • Graceful degradation
  4. Monitor and Alert

    • Track error rates
    • Set up alerts
    • Monitor response times

Next Steps

  1. Security Guide
  2. Webhooks Guide
  3. Integration Overview