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