try-error Documentation

Real-World Examples

Complex scenarios and production-ready patterns using try-error

E-commerce Order Processing

A complete order processing system demonstrating error handling across multiple services, payment processing, inventory management, and notification systems.

Order Service

Order Processing Pipelinetypescript
1import { tryAsync, isTryError, createTryError, flatMapResult } from 'try-error';
2
3interface Order {
4  id: string;
5  userId: string;
6  items: OrderItem[];
7  total: number;
8  status: 'pending' | 'processing' | 'completed' | 'failed';
9}
10
11interface OrderItem {
12  productId: string;
13  quantity: number;
14  price: number;
15}
16
17class OrderService {
18  async processOrder(orderData: Partial<Order>): Promise<TryResult<Order, TryError>> {
19    // Validate order data
20    const validationResult = await this.validateOrder(orderData);
21    if (isTryError(validationResult)) {
22      return validationResult;
23    }
24
25    // Check inventory availability
26    const inventoryResult = await flatMapResult(validationResult, order =>
27      this.checkInventory(order.items)
28    );
29    if (isTryError(inventoryResult)) {
30      return inventoryResult;
31    }
32
33    // Calculate pricing and taxes
34    const pricingResult = await flatMapResult(inventoryResult, order =>
35      this.calculatePricing(order)
36    );
37    if (isTryError(pricingResult)) {
38      return pricingResult;
39    }
40
41    // Process payment
42    const paymentResult = await flatMapResult(pricingResult, order =>
43      this.processPayment(order)
44    );
45    if (isTryError(paymentResult)) {
46      // Rollback inventory reservation
47      await this.releaseInventory(inventoryResult.items);
48      return paymentResult;
49    }
50
51    // Reserve inventory
52    const reservationResult = await flatMapResult(paymentResult, order =>
53      this.reserveInventory(order.items)
54    );
55    if (isTryError(reservationResult)) {
56      // Rollback payment
57      await this.refundPayment(paymentResult.paymentId);
58      return reservationResult;
59    }
60
61    // Create order record
62    const orderResult = await flatMapResult(reservationResult, order =>
63      this.createOrderRecord(order)
64    );
65    if (isTryError(orderResult)) {
66      // Rollback everything
67      await this.releaseInventory(reservationResult.items);
68      await this.refundPayment(paymentResult.paymentId);
69      return orderResult;
70    }
71
72    // Send confirmation notifications
73    await this.sendOrderConfirmation(orderResult);
74
75    return orderResult;
76  }
77
78  private async validateOrder(orderData: Partial<Order>): Promise<TryResult<Order, TryError>> {
79    return tryAsync(async () => {
80      if (!orderData.userId) {
81        throw createTryError('ValidationError', 'User ID is required', {
82          field: 'userId',
83          value: orderData.userId
84        });
85      }
86
87      if (!orderData.items || orderData.items.length === 0) {
88        throw createTryError('ValidationError', 'Order must contain at least one item', {
89          field: 'items',
90          value: orderData.items
91        });
92      }
93
94      // Validate each item
95      for (const item of orderData.items) {
96        if (item.quantity <= 0) {
97          throw createTryError('ValidationError', 'Item quantity must be positive', {
98            field: 'quantity',
99            productId: item.productId,
100            value: item.quantity
101          });
102        }
103      }
104
105      return {
106        id: generateOrderId(),
107        userId: orderData.userId,
108        items: orderData.items,
109        total: 0, // Will be calculated later
110        status: 'pending'
111      } as Order;
112    });
113  }
114
115  private async checkInventory(items: OrderItem[]): Promise<TryResult<Order, TryError>> {
116    return tryAsync(async () => {
117      for (const item of items) {
118        const availability = await this.inventoryService.checkAvailability(item.productId);
119        
120        if (availability < item.quantity) {
121          throw createTryError('InventoryError', 'Insufficient inventory', {
122            productId: item.productId,
123            requested: item.quantity,
124            available: availability
125          });
126        }
127      }
128
129      return { items } as Order;
130    });
131  }
132
133  private async processPayment(order: Order): Promise<TryResult<Order & { paymentId: string }, TryError>> {
134    return tryAsync(async () => {
135      const paymentResult = await this.paymentService.processPayment({
136        amount: order.total,
137        currency: 'USD',
138        userId: order.userId,
139        orderId: order.id
140      });
141
142      if (!paymentResult.success) {
143        throw createTryError('PaymentError', 'Payment processing failed', {
144          orderId: order.id,
145          amount: order.total,
146          reason: paymentResult.error,
147          retryable: paymentResult.retryable
148        });
149      }
150
151      return {
152        ...order,
153        paymentId: paymentResult.transactionId
154      };
155    });
156  }
157}

Error Recovery & Rollback

Comprehensive Error Recoverytypescript
1class OrderService {
2  async processOrderWithRecovery(orderData: Partial<Order>): Promise<TryResult<Order, TryError>> {
3    const rollbackActions: (() => Promise<void>)[] = [];
4
5    try {
6      // Step 1: Validate order
7      const validationResult = await this.validateOrder(orderData);
8      if (isTryError(validationResult)) {
9        return validationResult;
10      }
11
12      // Step 2: Reserve inventory
13      const inventoryResult = await this.reserveInventory(validationResult.items);
14      if (isTryError(inventoryResult)) {
15        return inventoryResult;
16      }
17      rollbackActions.push(() => this.releaseInventory(validationResult.items));
18
19      // Step 3: Process payment
20      const paymentResult = await this.processPayment(validationResult);
21      if (isTryError(paymentResult)) {
22        await this.executeRollback(rollbackActions);
23        return paymentResult;
24      }
25      rollbackActions.push(() => this.refundPayment(paymentResult.paymentId));
26
27      // Step 4: Create order
28      const orderResult = await this.createOrderRecord({
29        ...validationResult,
30        paymentId: paymentResult.paymentId
31      });
32      if (isTryError(orderResult)) {
33        await this.executeRollback(rollbackActions);
34        return orderResult;
35      }
36
37      // Step 5: Send notifications (non-critical)
38      const notificationResult = await this.sendOrderConfirmation(orderResult);
39      if (isTryError(notificationResult)) {
40        // Log but don't fail the order
41        console.warn('Failed to send order confirmation:', notificationResult.message);
42      }
43
44      return orderResult;
45
46    } catch (error) {
47      await this.executeRollback(rollbackActions);
48      return createTryError('OrderProcessingError', 'Unexpected error during order processing', {
49        originalError: error,
50        rollbackExecuted: true
51      });
52    }
53  }
54
55  private async executeRollback(actions: (() => Promise<void>)[]): Promise<void> {
56    // Execute rollback actions in reverse order
57    for (const action of actions.reverse()) {
58      try {
59        await action();
60      } catch (rollbackError) {
61        console.error('Rollback action failed:', rollbackError);
62        // Continue with other rollback actions
63      }
64    }
65  }
66
67  // Retry with exponential backoff for transient failures
68  async processOrderWithRetry(orderData: Partial<Order>, maxAttempts = 3): Promise<TryResult<Order, TryError>> {
69    let lastError: TryError;
70
71    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
72      const result = await this.processOrderWithRecovery(orderData);
73
74      if (!isTryError(result)) {
75        return result;
76      }
77
78      lastError = result;
79
80      // Don't retry validation errors or payment failures
81      if (hasErrorType(result, 'ValidationError') || 
82          hasErrorType(result, 'PaymentError')) {
83        break;
84      }
85
86      // Only retry on network errors or temporary failures
87      if (hasErrorType(result, 'NetworkError') || 
88          hasErrorType(result, 'InventoryError')) {
89        
90        if (attempt < maxAttempts) {
91          const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
92          await new Promise(resolve => setTimeout(resolve, delay));
93          console.log(`Retrying order processing, attempt ${attempt + 1}/${maxAttempts}`);
94        }
95      } else {
96        break;
97      }
98    }
99
100    return lastError!;
101  }
102}

Microservices Communication

Handling errors in distributed systems with circuit breakers, timeouts, and fallback strategies.

Service Client with Circuit Breaker

Resilient Service Communicationtypescript
1import { tryAsync, isTryError, createTryError, timeout, retry } from 'try-error';
2
3interface CircuitBreakerState {
4  state: 'closed' | 'open' | 'half-open';
5  failureCount: number;
6  lastFailureTime: number;
7  successCount: number;
8}
9
10class ServiceClient {
11  private circuitBreaker: Map<string, CircuitBreakerState> = new Map();
12  private readonly failureThreshold = 5;
13  private readonly recoveryTimeout = 30000; // 30 seconds
14  private readonly requestTimeout = 5000; // 5 seconds
15
16  async callService<T>(
17    serviceName: string,
18    operation: () => Promise<T>,
19    fallback?: () => Promise<T>
20  ): Promise<TryResult<T, TryError>> {
21    
22    // Check circuit breaker
23    const circuitState = this.getCircuitState(serviceName);
24    if (circuitState.state === 'open') {
25      if (Date.now() - circuitState.lastFailureTime < this.recoveryTimeout) {
26        return this.handleCircuitOpen(serviceName, fallback);
27      } else {
28        // Try to recover - move to half-open
29        circuitState.state = 'half-open';
30        circuitState.successCount = 0;
31      }
32    }
33
34    // Execute the operation with timeout and retry
35    const result = await retry(
36      () => timeout(operation, this.requestTimeout),
37      {
38        maxAttempts: 3,
39        delay: 1000,
40        backoff: 'exponential',
41        shouldRetry: (error) => {
42          return hasErrorType(error, 'NetworkError') || 
43                 hasErrorType(error, 'TimeoutError');
44        }
45      }
46    );
47
48    // Update circuit breaker based on result
49    this.updateCircuitBreaker(serviceName, result);
50
51    // If operation failed and we have a fallback, try it
52    if (isTryError(result) && fallback) {
53      console.warn(`Service ${serviceName} failed, using fallback:`, result.message);
54      return tryAsync(fallback);
55    }
56
57    return result;
58  }
59
60  private getCircuitState(serviceName: string): CircuitBreakerState {
61    if (!this.circuitBreaker.has(serviceName)) {
62      this.circuitBreaker.set(serviceName, {
63        state: 'closed',
64        failureCount: 0,
65        lastFailureTime: 0,
66        successCount: 0
67      });
68    }
69    return this.circuitBreaker.get(serviceName)!;
70  }
71
72  private updateCircuitBreaker<T>(serviceName: string, result: TryResult<T, TryError>): void {
73    const state = this.getCircuitState(serviceName);
74
75    if (isTryError(result)) {
76      state.failureCount++;
77      state.lastFailureTime = Date.now();
78      state.successCount = 0;
79
80      // Open circuit if failure threshold reached
81      if (state.failureCount >= this.failureThreshold) {
82        state.state = 'open';
83        console.warn(`Circuit breaker opened for service: ${serviceName}`);
84      }
85    } else {
86      // Success
87      if (state.state === 'half-open') {
88        state.successCount++;
89        // Close circuit after successful recovery
90        if (state.successCount >= 2) {
91          state.state = 'closed';
92          state.failureCount = 0;
93          console.info(`Circuit breaker closed for service: ${serviceName}`);
94        }
95      } else {
96        state.failureCount = 0;
97      }
98    }
99  }
100
101  private async handleCircuitOpen<T>(
102    serviceName: string, 
103    fallback?: () => Promise<T>
104  ): Promise<TryResult<T, TryError>> {
105    if (fallback) {
106      console.info(`Circuit breaker open for ${serviceName}, using fallback`);
107      return tryAsync(fallback);
108    }
109
110    return createTryError('CircuitBreakerError', `Service ${serviceName} is unavailable`, {
111      serviceName,
112      state: 'open',
113      retryAfter: this.recoveryTimeout
114    });
115  }
116}
117
118// Usage example
119class UserService {
120  private serviceClient = new ServiceClient();
121
122  async getUserProfile(userId: string): Promise<TryResult<UserProfile, TryError>> {
123    return this.serviceClient.callService(
124      'user-profile-service',
125      () => this.fetchUserProfileFromAPI(userId),
126      () => this.getUserProfileFromCache(userId)
127    );
128  }
129
130  async getUserPreferences(userId: string): Promise<TryResult<UserPreferences, TryError>> {
131    return this.serviceClient.callService(
132      'user-preferences-service',
133      () => this.fetchUserPreferencesFromAPI(userId),
134      () => this.getDefaultUserPreferences()
135    );
136  }
137
138  private async fetchUserProfileFromAPI(userId: string): Promise<UserProfile> {
139    const response = await fetch(`/api/users/${userId}/profile`);
140    if (!response.ok) {
141      throw createTryError('NetworkError', 'Failed to fetch user profile', {
142        userId,
143        status: response.status,
144        statusText: response.statusText
145      });
146    }
147    return response.json();
148  }
149
150  private async getUserProfileFromCache(userId: string): Promise<UserProfile> {
151    const cached = await this.cache.get(`user-profile:${userId}`);
152    if (!cached) {
153      throw createTryError('CacheError', 'User profile not found in cache', { userId });
154    }
155    return JSON.parse(cached);
156  }
157}

Data Processing Pipeline

A robust data processing pipeline with validation, transformation, and error recovery.

ETL Pipeline

Data Processing with Error Handlingtypescript
1import { tryAsync, isTryError, combineResults, sequenceResults } from 'try-error';
2
3interface DataRecord {
4  id: string;
5  source: string;
6  data: Record<string, any>;
7  timestamp: Date;
8}
9
10interface ProcessingResult {
11  processed: DataRecord[];
12  failed: Array<{ record: DataRecord; error: TryError }>;
13  summary: {
14    total: number;
15    successful: number;
16    failed: number;
17    duration: number;
18  };
19}
20
21class DataProcessor {
22  async processBatch(records: DataRecord[]): Promise<TryResult<ProcessingResult, TryError>> {
23    const startTime = Date.now();
24    
25    return tryAsync(async () => {
26      const results = await Promise.all(
27        records.map(record => this.processRecord(record))
28      );
29
30      const processed: DataRecord[] = [];
31      const failed: Array<{ record: DataRecord; error: TryError }> = [];
32
33      results.forEach((result, index) => {
34        if (isTryError(result)) {
35          failed.push({ record: records[index], error: result });
36        } else {
37          processed.push(result);
38        }
39      });
40
41      const duration = Date.now() - startTime;
42
43      // Log processing summary
44      console.info('Batch processing completed:', {
45        total: records.length,
46        successful: processed.length,
47        failed: failed.length,
48        duration
49      });
50
51      return {
52        processed,
53        failed,
54        summary: {
55          total: records.length,
56          successful: processed.length,
57          failed: failed.length,
58          duration
59        }
60      };
61    });
62  }
63
64  private async processRecord(record: DataRecord): Promise<TryResult<DataRecord, TryError>> {
65    // Step 1: Validate record
66    const validationResult = await this.validateRecord(record);
67    if (isTryError(validationResult)) {
68      return validationResult;
69    }
70
71    // Step 2: Transform data
72    const transformResult = await this.transformRecord(validationResult);
73    if (isTryError(transformResult)) {
74      return transformResult;
75    }
76
77    // Step 3: Enrich with external data
78    const enrichResult = await this.enrichRecord(transformResult);
79    if (isTryError(enrichResult)) {
80      // Enrichment failure is not critical - continue with original data
81      console.warn(`Failed to enrich record ${record.id}:`, enrichResult.message);
82      return transformResult;
83    }
84
85    // Step 4: Save to database
86    const saveResult = await this.saveRecord(enrichResult);
87    if (isTryError(saveResult)) {
88      return saveResult;
89    }
90
91    return enrichResult;
92  }
93
94  private async validateRecord(record: DataRecord): Promise<TryResult<DataRecord, TryError>> {
95    return tryAsync(async () => {
96      // Required fields validation
97      if (!record.id) {
98        throw createTryError('ValidationError', 'Record ID is required', {
99          recordId: record.id,
100          field: 'id'
101        });
102      }
103
104      if (!record.source) {
105        throw createTryError('ValidationError', 'Record source is required', {
106          recordId: record.id,
107          field: 'source'
108        });
109      }
110
111      // Data type validation
112      if (typeof record.data !== 'object' || record.data === null) {
113        throw createTryError('ValidationError', 'Record data must be an object', {
114          recordId: record.id,
115          field: 'data',
116          type: typeof record.data
117        });
118      }
119
120      // Business rule validation
121      if (record.source === 'api' && !record.data.userId) {
122        throw createTryError('ValidationError', 'API records must include userId', {
123          recordId: record.id,
124          source: record.source,
125          field: 'userId'
126        });
127      }
128
129      return record;
130    });
131  }
132
133  private async transformRecord(record: DataRecord): Promise<TryResult<DataRecord, TryError>> {
134    return tryAsync(async () => {
135      const transformedData = { ...record.data };
136
137      // Normalize field names
138      if (transformedData.user_id) {
139        transformedData.userId = transformedData.user_id;
140        delete transformedData.user_id;
141      }
142
143      // Convert timestamps
144      if (transformedData.created_at) {
145        transformedData.createdAt = new Date(transformedData.created_at);
146        delete transformedData.created_at;
147      }
148
149      // Validate transformed data
150      if (transformedData.email && !this.isValidEmail(transformedData.email)) {
151        throw createTryError('TransformationError', 'Invalid email format after transformation', {
152          recordId: record.id,
153          email: transformedData.email
154        });
155      }
156
157      return {
158        ...record,
159        data: transformedData
160      };
161    });
162  }
163
164  private async enrichRecord(record: DataRecord): Promise<TryResult<DataRecord, TryError>> {
165    return tryAsync(async () => {
166      const enrichedData = { ...record.data };
167
168      // Enrich with user data if userId is present
169      if (enrichedData.userId) {
170        const userResult = await this.fetchUserData(enrichedData.userId);
171        if (!isTryError(userResult)) {
172          enrichedData.userProfile = userResult;
173        }
174      }
175
176      // Enrich with geolocation if IP is present
177      if (enrichedData.ipAddress) {
178        const locationResult = await this.fetchLocationData(enrichedData.ipAddress);
179        if (!isTryError(locationResult)) {
180          enrichedData.location = locationResult;
181        }
182      }
183
184      return {
185        ...record,
186        data: enrichedData
187      };
188    });
189  }
190
191  private async saveRecord(record: DataRecord): Promise<TryResult<void, TryError>> {
192    return tryAsync(async () => {
193      await this.database.save('processed_records', record);
194    });
195  }
196
197  private isValidEmail(email: string): boolean {
198    const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/;
199    return emailRegex.test(email);
200  }
201}

CLI Application

A command-line tool with comprehensive error handling, user-friendly messages, and graceful degradation.

File Processing CLI

CLI with Error Handlingtypescript
1#!/usr/bin/env node
2import { tryAsync, isTryError, createTryError, hasErrorType } from 'try-error';
3import { promises as fs } from 'fs';
4import path from 'path';
5
6interface CLIOptions {
7  input: string;
8  output?: string;
9  format: 'json' | 'csv' | 'xml';
10  verbose: boolean;
11  force: boolean;
12}
13
14class FileProcessorCLI {
15  async run(args: string[]): Promise<void> {
16    const optionsResult = this.parseArguments(args);
17    if (isTryError(optionsResult)) {
18      this.handleError(optionsResult);
19      process.exit(1);
20    }
21
22    const options = optionsResult;
23    
24    if (options.verbose) {
25      console.log('Starting file processing with options:', options);
26    }
27
28    const result = await this.processFile(options);
29    if (isTryError(result)) {
30      this.handleError(result);
31      process.exit(1);
32    }
33
34    console.log('✅ File processing completed successfully!');
35    if (options.output) {
36      console.log(`📁 Output saved to: ${options.output}`);
37    }
38  }
39
40  private parseArguments(args: string[]): TryResult<CLIOptions, TryError> {
41    try {
42      const options: Partial<CLIOptions> = {
43        verbose: false,
44        force: false,
45        format: 'json'
46      };
47
48      for (let i = 0; i < args.length; i++) {
49        const arg = args[i];
50        
51        switch (arg) {
52          case '--input':
53          case '-i':
54            options.input = args[++i];
55            break;
56          case '--output':
57          case '-o':
58            options.output = args[++i];
59            break;
60          case '--format':
61          case '-f':
62            const format = args[++i];
63            if (!['json', 'csv', 'xml'].includes(format)) {
64              throw createTryError('ValidationError', 'Invalid format specified', {
65                format,
66                validFormats: ['json', 'csv', 'xml']
67              });
68            }
69            options.format = format as 'json' | 'csv' | 'xml';
70            break;
71          case '--verbose':
72          case '-v':
73            options.verbose = true;
74            break;
75          case '--force':
76            options.force = true;
77            break;
78          case '--help':
79          case '-h':
80            this.showHelp();
81            process.exit(0);
82            break;
83          default:
84            if (arg.startsWith('-')) {
85              throw createTryError('ValidationError', `Unknown option: ${arg}`, {
86                option: arg
87              });
88            }
89        }
90      }
91
92      if (!options.input) {
93        throw createTryError('ValidationError', 'Input file is required', {
94          hint: 'Use --input or -i to specify the input file'
95        });
96      }
97
98      return options as CLIOptions;
99    } catch (error) {
100      if (isTryError(error)) {
101        return error;
102      }
103      return createTryError('ParseError', 'Failed to parse command line arguments', {
104        originalError: error
105      });
106    }
107  }
108
109  private async processFile(options: CLIOptions): Promise<TryResult<void, TryError>> {
110    // Step 1: Validate input file
111    const inputValidation = await this.validateInputFile(options.input);
112    if (isTryError(inputValidation)) {
113      return inputValidation;
114    }
115
116    // Step 2: Read and parse input file
117    const readResult = await this.readInputFile(options.input);
118    if (isTryError(readResult)) {
119      return readResult;
120    }
121
122    // Step 3: Process data
123    const processResult = await this.processData(readResult, options);
124    if (isTryError(processResult)) {
125      return processResult;
126    }
127
128    // Step 4: Write output file
129    if (options.output) {
130      const writeResult = await this.writeOutputFile(options.output, processResult, options);
131      if (isTryError(writeResult)) {
132        return writeResult;
133      }
134    } else {
135      // Output to console
136      console.log(JSON.stringify(processResult, null, 2));
137    }
138
139    return undefined as any; // Success
140  }
141
142  private async validateInputFile(inputPath: string): Promise<TryResult<void, TryError>> {
143    return tryAsync(async () => {
144      try {
145        const stats = await fs.stat(inputPath);
146        
147        if (!stats.isFile()) {
148          throw createTryError('FileError', 'Input path is not a file', {
149            path: inputPath,
150            type: 'directory'
151          });
152        }
153
154        if (stats.size === 0) {
155          throw createTryError('FileError', 'Input file is empty', {
156            path: inputPath,
157            size: stats.size
158          });
159        }
160
161        if (stats.size > 100 * 1024 * 1024) { // 100MB limit
162          throw createTryError('FileError', 'Input file is too large', {
163            path: inputPath,
164            size: stats.size,
165            maxSize: 100 * 1024 * 1024
166          });
167        }
168
169      } catch (error) {
170        if (error.code === 'ENOENT') {
171          throw createTryError('FileError', 'Input file does not exist', {
172            path: inputPath,
173            code: error.code
174          });
175        }
176        if (error.code === 'EACCES') {
177          throw createTryError('FileError', 'Permission denied accessing input file', {
178            path: inputPath,
179            code: error.code
180          });
181        }
182        throw error;
183      }
184    });
185  }
186
187  private async readInputFile(inputPath: string): Promise<TryResult<any[], TryError>> {
188    return tryAsync(async () => {
189      const content = await fs.readFile(inputPath, 'utf-8');
190      const ext = path.extname(inputPath).toLowerCase();
191
192      switch (ext) {
193        case '.json':
194          try {
195            const data = JSON.parse(content);
196            return Array.isArray(data) ? data : [data];
197          } catch (parseError) {
198            throw createTryError('ParseError', 'Invalid JSON format', {
199              path: inputPath,
200              error: parseError.message
201            });
202          }
203        
204        case '.csv':
205          return this.parseCSV(content);
206        
207        default:
208          throw createTryError('FileError', 'Unsupported file format', {
209            path: inputPath,
210            extension: ext,
211            supportedFormats: ['.json', '.csv']
212          });
213      }
214    });
215  }
216
217  private handleError(error: TryError): void {
218    console.error('❌ Error:', error.message);
219
220    if (hasErrorType(error, 'ValidationError')) {
221      console.error('💡 Validation issue:', error.context);
222      if (error.context?.hint) {
223        console.error('💡 Hint:', error.context.hint);
224      }
225    } else if (hasErrorType(error, 'FileError')) {
226      console.error('📁 File issue:', error.context);
227      if (error.context?.code === 'ENOENT') {
228        console.error('💡 Make sure the file path is correct and the file exists');
229      } else if (error.context?.code === 'EACCES') {
230        console.error('💡 Check file permissions or run with appropriate privileges');
231      }
232    } else if (hasErrorType(error, 'ParseError')) {
233      console.error('🔍 Parse issue:', error.context);
234      console.error('💡 Check the file format and content structure');
235    }
236
237    if (error.context?.originalError) {
238      console.error('🔧 Technical details:', error.context.originalError);
239    }
240  }
241
242  private showHelp(): void {
243    console.log(`
244File Processor CLI
245
246Usage: file-processor [options]
247
248Options:
249  -i, --input <file>     Input file path (required)
250  -o, --output <file>    Output file path (optional, prints to console if not specified)
251  -f, --format <format>  Output format: json, csv, xml (default: json)
252  -v, --verbose          Enable verbose logging
253  --force                Overwrite output file if it exists
254  -h, --help             Show this help message
255
256Examples:
257  file-processor -i data.json -o processed.json
258  file-processor -i data.csv -o result.xml -f xml
259  file-processor -i input.json --verbose
260`);
261  }
262}
263
264// CLI entry point
265if (require.main === module) {
266  const cli = new FileProcessorCLI();
267  cli.run(process.argv.slice(2));
268}

Production Best Practices

✅ Error Handling Patterns

  • • Use circuit breakers for external service calls
  • • Implement comprehensive rollback mechanisms
  • • Provide meaningful fallback strategies
  • • Add retry logic with exponential backoff
  • • Include detailed context in error objects
  • • Log errors with appropriate severity levels

🔧 Operational Considerations

  • • Monitor error rates and patterns
  • • Set up alerts for critical error types
  • • Implement health checks and readiness probes
  • • Use structured logging for better observability
  • • Track error recovery success rates
  • • Implement graceful degradation strategies

⚡ Performance Tips

  • • Use timeouts to prevent hanging operations
  • • Implement request deduplication for retries
  • • Cache fallback data when possible
  • • Use async processing for non-critical operations
  • • Batch operations to reduce overhead
  • • Monitor and optimize error handling paths

Related Pages

Basic Examples

Start with fundamental patterns and use cases

View Basic Examples →

Migration Guide

Learn how to adopt try-error in existing projects

View Migration Guide →