Get Started
StateSet One Guides
- Orders Management Quickstart
- Order settlements
- Wholesale Quickstart
- Returns Quickstart
- Warranties Quickstart
- Subscriptions Quickstart
- Manufacturing and Production Quickstart
- Warehouse Quickstart
- COGS Quickstart Guide
- Supplier Quickstart
- Inventory Management Quickstart
- Error Handling Best Practices
- API Rate Limiting & Optimization
- Performance Optimization Guide
- Comprehensive Testing Guide
StateSet ResponseCX Guides
- Getting Started with ResponseCX
- Agent Training Guide
- Agent Objectives, Goals, Metrics & Rewards Guide
- Multi-Agent System Architectures
- Reinforcement Learning Platform Overview
- GRPO Agent Framework
- Knowledge Base Quickstart
- RAG Quickstart
- Agents Quickstart
- Agent Attributes & Personality
- Agent Rules Quickstart
- Examples Quickstart
- Evaluations
- Agent Schedules & Automation
- Agent Functions Quickstart
- Shopify Product Quickstart
- Gorgias Ticket Quickstart
- Vision Quickstart
- Voice AI Quickstart
- Synthetic Data Studio
- StateSet Synthetic Data Studio Architecture Guide
StateSet Commerce Network Guides
StateSet ReSponse API Documentation
StateSet One Guides
Error Handling Best Practices
Comprehensive guide to handling errors and implementing robust error recovery in StateSet applications
Error Handling Best Practices
Robust error handling is crucial for building reliable applications with StateSet. This guide covers best practices for handling errors, implementing retry logic, and monitoring your applications effectively.
Overview
StateSet APIs return structured error responses that include:
- Error codes: Consistent numeric or string identifiers
- Error messages: Human-readable descriptions
- Error details: Additional context and debugging information
- Request IDs: Unique identifiers for tracing issues
Error Response Structure
All StateSet API errors follow this consistent format:
Copy
Ask AI
{
"error": {
"type": "validation_error",
"code": "INVALID_PARAMETER",
"message": "The provided email address is invalid",
"details": {
"field": "customer_email",
"provided": "invalid-email",
"expected": "valid email format"
},
"request_id": "req_1H9x2C2QlDjKpM2WYw5"
}
}
Common Error Types
1. Authentication Errors (401)
Copy
Ask AI
import winston from 'winston';
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'app.log' }),
new winston.transports.Console()
]
});
try {
const response = await statesetClient.orders.list();
} catch (error) {
if (error.status === 401) {
logger.error('Authentication failed', {
error: error.message,
apiKey: process.env.STATESET_API_KEY?.substring(0, 12) + '...',
requestId: error.requestId
});
// Handle token refresh or re-authentication
await refreshApiKey();
return retryRequest();
}
}
2. Validation Errors (400)
Copy
Ask AI
const createOrderWithValidation = async (orderData) => {
try {
return await statesetClient.orders.create(orderData);
} catch (error) {
if (error.status === 400) {
logger.warn('Order validation failed', {
validationErrors: error.details,
orderData: sanitizeOrderData(orderData),
requestId: error.requestId
});
// Extract specific field errors
const fieldErrors = error.details?.fields || {};
throw new ValidationError('Order validation failed', fieldErrors);
}
throw error;
}
};
// Custom error classes for better error handling
class ValidationError extends Error {
constructor(message, fieldErrors) {
super(message);
this.name = 'ValidationError';
this.fieldErrors = fieldErrors;
}
}
3. Rate Limiting (429)
Copy
Ask AI
const retryWithBackoff = async (operation, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
if (error.status === 429) {
const retryAfter = error.headers?.['retry-after'] || Math.pow(2, attempt);
logger.warn('Rate limit exceeded, retrying', {
attempt,
retryAfter,
requestId: error.requestId
});
if (attempt === maxRetries) {
throw new Error(`Rate limit exceeded after ${maxRetries} attempts`);
}
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
} else {
throw error;
}
}
}
};
// Usage
const orders = await retryWithBackoff(() =>
statesetClient.orders.list({ limit: 100 })
);
4. Server Errors (500+)
Copy
Ask AI
const handleServerError = async (operation, context) => {
try {
return await operation();
} catch (error) {
if (error.status >= 500) {
logger.error('Server error encountered', {
status: error.status,
message: error.message,
context,
requestId: error.requestId,
timestamp: new Date().toISOString()
});
// Send to error tracking service
if (process.env.SENTRY_DSN) {
Sentry.captureException(error, {
tags: { operation: context.operation },
extra: { requestId: error.requestId }
});
}
// Return user-friendly error
throw new Error('Service temporarily unavailable. Please try again later.');
}
throw error;
}
};
Comprehensive Error Handler
Create a centralized error handler for consistent error processing:
Copy
Ask AI
class StateSetErrorHandler {
constructor(options = {}) {
this.logger = options.logger || winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [new winston.transports.Console()]
});
this.retryAttempts = options.retryAttempts || 3;
this.enableMetrics = options.enableMetrics || false;
}
async handleApiCall(operation, context = {}) {
const startTime = Date.now();
try {
const result = await this.executeWithRetry(operation, context);
if (this.enableMetrics) {
this.recordMetric('api_call_success', {
operation: context.operation,
duration: Date.now() - startTime
});
}
return result;
} catch (error) {
const errorInfo = {
operation: context.operation,
error: error.message,
status: error.status,
requestId: error.requestId,
duration: Date.now() - startTime,
context
};
this.logger.error('API call failed', errorInfo);
if (this.enableMetrics) {
this.recordMetric('api_call_error', errorInfo);
}
throw this.transformError(error);
}
}
async executeWithRetry(operation, context, attempt = 1) {
try {
return await operation();
} catch (error) {
if (this.shouldRetry(error, attempt)) {
const delay = this.calculateBackoffDelay(attempt);
this.logger.warn('Retrying API call', {
operation: context.operation,
attempt,
delay,
error: error.message
});
await this.sleep(delay);
return this.executeWithRetry(operation, context, attempt + 1);
}
throw error;
}
}
shouldRetry(error, attempt) {
if (attempt >= this.retryAttempts) return false;
// Retry on rate limits, server errors, and network issues
return [429, 500, 502, 503, 504].includes(error.status) ||
error.code === 'NETWORK_ERROR' ||
error.code === 'TIMEOUT';
}
calculateBackoffDelay(attempt) {
// Exponential backoff with jitter
const baseDelay = Math.pow(2, attempt) * 1000;
const jitter = Math.random() * 1000;
return baseDelay + jitter;
}
transformError(error) {
// Transform API errors into application-specific errors
switch (error.status) {
case 400:
return new ValidationError(error.message, error.details);
case 401:
return new AuthenticationError(error.message);
case 403:
return new AuthorizationError(error.message);
case 404:
return new NotFoundError(error.message);
case 429:
return new RateLimitError(error.message);
default:
return new ApiError(error.message, error.status);
}
}
recordMetric(name, data) {
// Implement your metrics collection here
// Examples: DataDog, Prometheus, CloudWatch
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Usage
const errorHandler = new StateSetErrorHandler({
logger: winston.createLogger({...}),
retryAttempts: 3,
enableMetrics: true
});
const orders = await errorHandler.handleApiCall(
() => statesetClient.orders.list(),
{ operation: 'list_orders' }
);
Webhook Error Handling
For webhook endpoints, implement proper error handling and retry logic:
Copy
Ask AI
import express from 'express';
import crypto from 'crypto';
const app = express();
app.post('/webhooks/stateset', express.raw({ type: 'application/json' }), async (req, res) => {
try {
// Verify webhook signature
const signature = req.headers['x-stateset-signature'];
if (!verifyWebhookSignature(req.body, signature)) {
logger.warn('Invalid webhook signature', {
signature,
ip: req.ip,
userAgent: req.headers['user-agent']
});
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body);
logger.info('Webhook received', {
eventType: event.type,
eventId: event.id,
timestamp: event.created
});
// Process webhook with timeout
await Promise.race([
processWebhookEvent(event),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Webhook processing timeout')), 25000)
)
]);
res.status(200).json({ received: true });
} catch (error) {
logger.error('Webhook processing failed', {
error: error.message,
stack: error.stack,
body: req.body.toString(),
headers: req.headers
});
// Return 200 to prevent retries for permanent failures
if (error.name === 'ValidationError') {
return res.status(200).json({
error: 'Invalid event format',
processed: false
});
}
// Return 5xx for temporary failures to trigger retries
res.status(500).json({
error: 'Processing failed',
retry: true
});
}
});
const verifyWebhookSignature = (payload, signature) => {
const expectedSignature = crypto
.createHmac('sha256', process.env.STATESET_WEBHOOK_SECRET)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSignature, 'hex')
);
};
Error Monitoring & Alerting
Structured Logging
Copy
Ask AI
const createStructuredLogger = () => {
return winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
defaultMeta: {
service: 'stateset-integration',
environment: process.env.NODE_ENV,
version: process.env.APP_VERSION
},
transports: [
new winston.transports.File({
filename: 'error.log',
level: 'error'
}),
new winston.transports.File({
filename: 'combined.log'
}),
new winston.transports.Console({
format: winston.format.simple()
})
]
});
};
Error Tracking Integration
Copy
Ask AI
import * as Sentry from '@sentry/node';
// Initialize Sentry
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
integrations: [
new Sentry.Integrations.Http({ tracing: true }),
new Sentry.Integrations.Express({ app }),
],
tracesSampleRate: 0.1,
});
const reportError = (error, context = {}) => {
logger.error('Error reported to Sentry', {
error: error.message,
context,
errorId: Sentry.captureException(error, {
tags: {
component: 'stateset-integration',
operation: context.operation
},
extra: context
})
});
};
Testing Error Scenarios
Create comprehensive error handling tests:
Copy
Ask AI
import { jest } from '@jest/globals';
describe('StateSet Error Handling', () => {
let errorHandler;
let mockStateSetClient;
beforeEach(() => {
mockStateSetClient = {
orders: {
create: jest.fn(),
list: jest.fn()
}
};
errorHandler = new StateSetErrorHandler({
logger: createTestLogger(),
retryAttempts: 2
});
});
it('should retry on rate limit errors', async () => {
const rateLimitError = new Error('Rate limit exceeded');
rateLimitError.status = 429;
rateLimitError.headers = { 'retry-after': '1' };
mockStateSetClient.orders.list
.mockRejectedValueOnce(rateLimitError)
.mockResolvedValueOnce({ data: [] });
const result = await errorHandler.handleApiCall(
() => mockStateSetClient.orders.list(),
{ operation: 'list_orders' }
);
expect(mockStateSetClient.orders.list).toHaveBeenCalledTimes(2);
expect(result).toEqual({ data: [] });
});
it('should not retry on validation errors', async () => {
const validationError = new Error('Invalid email');
validationError.status = 400;
mockStateSetClient.orders.create.mockRejectedValue(validationError);
await expect(
errorHandler.handleApiCall(
() => mockStateSetClient.orders.create({}),
{ operation: 'create_order' }
)
).rejects.toThrow(ValidationError);
expect(mockStateSetClient.orders.create).toHaveBeenCalledTimes(1);
});
});
Best Practices Summary
- Use Structured Logging: Always log errors with context and structured data
- Implement Retry Logic: Automatically retry transient failures with exponential backoff
- Handle Rate Limits: Respect rate limits and implement proper backoff strategies
- Validate Early: Validate input data before making API calls
- Monitor Errors: Use error tracking services to monitor and alert on issues
- Test Error Paths: Write comprehensive tests for error scenarios
- Graceful Degradation: Provide fallback options when possible
- User-Friendly Messages: Transform technical errors into user-friendly messages
Additional Resources
On this page
- Error Handling Best Practices
- Overview
- Error Response Structure
- Common Error Types
- 1. Authentication Errors (401)
- 2. Validation Errors (400)
- 3. Rate Limiting (429)
- 4. Server Errors (500+)
- Comprehensive Error Handler
- Webhook Error Handling
- Error Monitoring & Alerting
- Structured Logging
- Error Tracking Integration
- Testing Error Scenarios
- Best Practices Summary
- Additional Resources
Assistant
Responses are generated using AI and may contain mistakes.