tryError Documentation
Configuration Reference
Configure tryError behavior and customize error handling for your application
📌 Quick Start: tryError is configured in your application code, not through config files. Call setupNode()
, setupReact()
, or configure()
at your app's entry point. See the Where to Configure section below.
💡 Do I need to configure tryError?
Short answer: No! tryError works perfectly out of the box without any configuration.
Configuration is optional and only needed when you want to:
- • Optimize performance for production (disable stack traces, etc.)
- • Set up error monitoring and reporting
- • Customize error behavior for your specific needs
- • Use environment-specific settings
Getting started? Just import and use trySync()
, tryAsync()
, and createTryError()
directly. Come back here when you need customization!
📍 Where to Configure tryError
Important: tryError does NOT use configuration files. Configuration happens in your application code at runtime.
Option 1: Application Entry Point (Recommended)
Configure tryError once at your application's entry point, before any other code runs.
Node.js/Express
1// At the very top of your entry file
2import { setupNode } from '@try-error/core/setup';
3
4// Configure before anything else
5setupNode();
6
7// Now import and use your app
8import express from 'express';
9const app = express();
10// ... rest of your app
React/Vite
1// At the very top of your entry file
2import { setupReact } from '@try-error/core/setup';
3
4// Configure before React
5setupReact();
6
7// Now import React
8import React from 'react';
9import ReactDOM from 'react-dom/client';
10import App from './App';
11
12ReactDOM.createRoot(...).render(<App />);
Next.js
1// For App Router: app/layout.tsx
2import { setupNextJs } from '@try-error/core/setup';
3
4// Simple setup (same config for both server and client)
5setupNextJs();
6
7// Advanced: Separate server/client configurations
8setupNextJs({
9 server: {
10 captureStackTrace: false,
11 onError: (error) => {
12 // Server-side logging
13 console.error('[Server Error]', error);
14 }
15 },
16 client: {
17 captureStackTrace: false,
18 onError: (error) => {
19 // Client-side error tracking
20 // window.Sentry?.captureException(error);
21 }
22 }
23});
24
25export default function RootLayout({
26 children,
27}: {
28 children: React.ReactNode;
29}) {
30 return (
31 <html lang="en">
32 <body>{children}</body>
33 </html>
34 );
35}
Option 2: Dedicated Configuration Module
For more complex configurations, create a dedicated module and import it early.
1// Create a configuration module
2import { configure } from '@try-error/core';
3
4// Your custom configuration
5configure({
6 captureStackTrace: process.env.NODE_ENV !== 'production',
7 onError: (error) => {
8 // Custom error handling
9 if (process.env.NODE_ENV === 'production') {
10 sendToSentry(error);
11 }
12 return error;
13 },
14 serializer: (error) => ({
15 type: error.type,
16 message: error.message,
17 timestamp: error.timestamp,
18 // Custom serialization
19 })
20});
21
22// Export for testing or reconfiguration
23export const tryErrorConfig = {
24 isConfigured: true
25};
1// Import configuration first
2import './config/tryError.config';
3
4// Then import everything else
5import express from 'express';
6import { routes } from './routes';
7
8const app = express();
9// ... rest of your app
Option 3: Environment-Based Configuration
Use environment variables to switch between configurations.
1import { configure, ConfigPresets } from '@try-error/core';
2
3// Configure based on environment
4switch (process.env.NODE_ENV) {
5 case 'production':
6 configure(ConfigPresets.production());
7 break;
8 case 'test':
9 configure(ConfigPresets.test());
10 break;
11 default:
12 configure(ConfigPresets.development());
13}
14
15// Or use the auto-setup
16import { autoSetup } from '@try-error/core/setup';
17autoSetup(); // Automatically detects environment
⚠️ Important Configuration Rules
- 1. Configure Once: Configure tryError only once per application. Multiple configurations will override each other.
- 2. Configure Early: Always configure before using any tryError functions (trySync, tryAsync, etc.).
- 3. No Config Files: tryError doesn't read from .tryerrorrc or similar files. All configuration is done in code.
- 4. Global Effect: Configuration affects all tryError usage globally in your application.
💡 Testing Tip
For testing, you might want to reconfigure tryError. Use a test setup file:
1import { configure } from '@try-error/core';
2
3beforeAll(() => {
4 configure({
5 captureStackTrace: true,
6 developmentMode: true,
7 onError: (error) => {
8 // Collect errors for assertions
9 global.testErrors.push(error);
10 return error;
11 }
12 });
13});
14
15// Add to jest.config.js or vitest.config.ts:
16// setupFilesAfterEnv: ['<rootDir>/test/setup.ts']
Quick Setup (Recommended)
Use our one-liner setup utilities for instant optimization with sensible defaults. These functions automatically configure tryError for your environment.
⚡ Environment-Specific Setup
1// Import setup utilities (tree-shakeable)
2import { setupNode, setupReact, setupNextJs, autoSetup } from '@try-error/core/setup';
3
4// Node.js/Express - Automatic environment detection
5setupNode(); // ✨ Optimized for dev/prod automatically
6
7// React/Vite - Browser-optimized configuration
8setupReact(); // ✨ Perfect for client-side apps
9
10// Next.js - Handles both SSR and client-side
11setupNextJs(); // ✨ Works for both server and client
12
13// Auto-detect environment (works everywhere)
14autoSetup(); // ✨ Detects Node.js, React, Next.js, etc.
15
16// High-performance (for critical applications)
17import { setupPerformance } from '@try-error/core/setup';
18setupPerformance(); // ✨ Maximum performance, minimal overhead
19
20// Testing environment
21import { setupTesting } from '@try-error/core/setup';
22setupTesting(); // ✨ Test-friendly configuration
🎯 Benefits of Quick Setup
- • Zero boilerplate: One line replaces 20+ lines of configuration
- • Environment-aware: Automatically optimizes for dev/prod/test
- • Best practices: Includes performance optimizations by default
- • Tree-shakeable: Only includes what you use
🔍 What happens under the hood?
Here's exactly what each setup function does when you call it:
setupNode()
1// Equivalent manual configuration:
2configure({
3 captureStackTrace: process.env.NODE_ENV !== 'production',
4 stackTraceLimit: process.env.NODE_ENV === 'production' ? 5 : 50,
5 developmentMode: process.env.NODE_ENV === 'development',
6
7 onError: (error) => {
8 if (process.env.NODE_ENV === 'production') {
9 // Minimal production logging
10 console.error(`[ERROR] ${error.type}: ${error.message}`);
11 } else {
12 // Detailed development logging
13 console.group(`🚨 TryError: ${error.type}`);
14 console.error('Message:', error.message);
15 console.error('Context:', error.context);
16 console.error('Stack:', error.stack);
17 console.groupEnd();
18 }
19 return error;
20 },
21
22 serializer: (error) => ({
23 type: error.type,
24 message: error.message,
25 timestamp: error.timestamp,
26 ...(process.env.NODE_ENV === 'development' && {
27 context: error.context,
28 stack: error.stack
29 })
30 })
31});
setupReact()
1// Equivalent manual configuration:
2configure({
3 captureStackTrace: import.meta.env.DEV, // Vite
4 stackTraceLimit: import.meta.env.PROD ? 3 : 20,
5 developmentMode: import.meta.env.DEV,
6
7 onError: (error) => {
8 if (import.meta.env.PROD) {
9 // Send to analytics in production
10 window.gtag?.('event', 'exception', {
11 description: `${error.type}: ${error.message}`,
12 fatal: false
13 });
14 } else {
15 // Development console logging
16 console.group(`🚨 TryError: ${error.type}`);
17 console.error('Message:', error.message);
18 console.error('Context:', error.context);
19 console.groupEnd();
20 }
21 return error;
22 },
23
24 serializer: (error) => ({
25 type: error.type,
26 message: error.message,
27 url: window.location.href,
28 userAgent: navigator.userAgent,
29 timestamp: error.timestamp
30 })
31});
setupPerformance()
1// Equivalent manual configuration:
2configure({
3 captureStackTrace: false, // Disabled for max performance
4 stackTraceLimit: 0, // No stack traces
5 developmentMode: false, // Production mode
6
7 onError: (error) => {
8 // Minimal logging only
9 console.error(`Error: ${error.type}`);
10 return error;
11 },
12
13 serializer: (error) => ({
14 type: error.type,
15 message: error.message,
16 timestamp: error.timestamp
17 // No context or stack for performance
18 })
19});
20
21// Also configures performance optimizations:
22configurePerformance({
23 errorCreation: {
24 cacheConstructors: true,
25 lazyStackTrace: true,
26 objectPooling: true,
27 poolSize: 100
28 },
29 contextCapture: {
30 maxContextSize: 1024 * 5, // 5KB limit
31 deepClone: false,
32 timeout: 50
33 },
34 memory: {
35 maxErrorHistory: 50,
36 useWeakRefs: true,
37 gcHints: true
38 }
39});
Setup with Custom Options
All setup functions accept custom options to override defaults.
1// Setup with custom error reporting
2setupNode({
3 onError: (error) => {
4 // Send to your monitoring service
5 sendToSentry(error);
6 sendToDatadog(error);
7 return error;
8 }
9});
10
11// React setup with analytics
12setupReact({
13 onError: (error) => {
14 // Send to analytics
15 gtag('event', 'exception', {
16 description: `${error.type}: ${error.message}`,
17 fatal: false
18 });
19 return error;
20 }
21});
22
23// Next.js with custom serialization
24setupNextJs({
25 serializer: (error) => ({
26 type: error.type,
27 message: error.message,
28 url: typeof window !== 'undefined' ? window.location.href : 'server',
29 timestamp: error.timestamp
30 })
31});
Custom Setup Function
Create your own setup function with organizational defaults.
1import { createCustomSetup } from '@try-error/core/setup';
2
3// Create your organization's standard setup
4const setupMyApp = createCustomSetup({
5 onError: (error) => sendToMyMonitoringService(error),
6 serializer: (error) => myCustomSerializer(error),
7 captureStackTrace: process.env.NODE_ENV !== 'production'
8});
9
10// Use in your applications
11setupMyApp(); // Uses your defaults
12setupMyApp({ developmentMode: true }); // Override specific options
Manual Configuration Guide
Want complete control? Here's how to configure tryError manually with all available options.
💡 When to use manual configuration
- • You need very specific behavior not covered by setup utilities
- • You're integrating with custom monitoring/logging systems
- • You want to understand exactly what's happening
- • You're building a library that uses tryError internally
Complete Configuration Interface
1interface TryErrorConfig {
2 /**
3 * Whether to capture stack traces (expensive operation)
4 * @default true in development, false in production
5 */
6 captureStackTrace?: boolean;
7
8 /**
9 * Maximum stack trace depth to capture
10 * @default 10
11 */
12 stackTraceLimit?: number;
13
14 /**
15 * Include source location in errors
16 * @default true
17 */
18 includeSource?: boolean;
19
20 /**
21 * Enable minimal error mode for ultra-lightweight errors
22 * Bypasses all expensive operations like stack trace capture
23 * @default false
24 */
25 minimalErrors?: boolean;
26
27 /**
28 * Skip timestamp generation (Date.now() calls)
29 * Useful for performance-critical paths
30 * @default false
31 */
32 skipTimestamp?: boolean;
33
34 /**
35 * Skip context processing
36 * Prevents deep cloning or processing of context objects
37 * @default false
38 */
39 skipContext?: boolean;
40
41 /**
42 * Default error type for untyped errors
43 * @default "Error"
44 */
45 defaultErrorType?: string;
46
47 /**
48 * Enable development mode features (verbose logging, etc.)
49 * @default false
50 */
51 developmentMode?: boolean;
52
53 /**
54 * Custom error serialization function
55 * Called when converting errors to JSON or for logging
56 */
57 serializer?: (error: TryError) => Record<string, unknown>;
58
59 /**
60 * Global error transformation hook
61 * Called for every error created, allows modification
62 */
63 onError?: (error: TryError) => TryError;
64
65 /**
66 * Performance optimization settings
67 * Configure advanced performance features
68 */
69 performance?: {
70 errorCreation?: {
71 objectPooling?: boolean;
72 poolSize?: number;
73 lazyStackTrace?: boolean;
74 lazySourceLocation?: boolean;
75 };
76 contextCapture?: {
77 maxDepth?: number;
78 maxProperties?: number;
79 excludePatterns?: string[];
80 };
81 memoryManagement?: {
82 maxErrorsInMemory?: number;
83 errorTTL?: number;
84 };
85 };
86}
Step-by-Step Manual Setup
1import { configure } from '@try-error/core';
2
3// Step 1: Basic configuration
4configure({
5 // Performance settings
6 captureStackTrace: process.env.NODE_ENV !== 'production',
7 stackTraceLimit: process.env.NODE_ENV === 'production' ? 5 : 50,
8 includeSource: true,
9
10 // Behavior settings
11 defaultErrorType: 'ApplicationError',
12 developmentMode: process.env.NODE_ENV === 'development',
13
14 // Custom serialization for logging/monitoring
15 serializer: (error) => {
16 const base = {
17 type: error.type,
18 message: error.message,
19 timestamp: error.timestamp,
20 source: error.source
21 };
22
23 // Include sensitive data only in development
24 if (process.env.NODE_ENV === 'development') {
25 return {
26 ...base,
27 context: error.context,
28 stack: error.stack,
29 cause: error.cause
30 };
31 }
32
33 // Production: minimal data
34 return base;
35 },
36
37 // Global error handling
38 onError: (error) => {
39 // Log to console
40 if (process.env.NODE_ENV === 'development') {
41 console.group(`🚨 ${error.type}`);
42 console.error('Message:', error.message);
43 console.error('Context:', error.context);
44 console.error('Stack:', error.stack);
45 console.groupEnd();
46 } else {
47 console.error(`[${error.type}] ${error.message}`);
48 }
49
50 // Send to monitoring services
51 if (process.env.NODE_ENV === 'production') {
52 // Example integrations
53 sendToSentry(error);
54 sendToDatadog(error);
55 sendToNewRelic(error);
56 }
57
58 // Analytics tracking
59 if (typeof window !== 'undefined' && window.gtag) {
60 window.gtag('event', 'exception', {
61 description: `${error.type}: ${error.message}`,
62 fatal: false
63 });
64 }
65
66 // Must return the error (can be modified)
67 return error;
68 }
69});
Configuration Option Details
captureStackTrace
Controls whether stack traces are captured when errors are created.
- • true: Full stack traces (useful for debugging)
- • false: No stack traces (better performance)
- • Recommendation: true in development, false in production
stackTraceLimit
Maximum number of stack frames to capture.
- • Higher values: More detailed traces, slower performance
- • Lower values: Less detail, better performance
- • Recommendation: 50 in development, 5 in production
serializer
Function that converts TryError objects to plain objects for logging/JSON.
1serializer: (error) => ({
2 // Always include these
3 type: error.type,
4 message: error.message,
5 timestamp: error.timestamp,
6
7 // Conditional fields
8 ...(error.context && { context: error.context }),
9 ...(error.source && { source: error.source }),
10 ...(error.stack && { stack: error.stack }),
11
12 // Custom fields
13 severity: getSeverityLevel(error.type),
14 userId: getCurrentUserId(),
15 sessionId: getSessionId()
16})
onError
Global hook called for every error. Use for logging, monitoring, and analytics.
1onError: (error) => {
2 // Rate limiting to prevent spam
3 if (shouldRateLimit(error.type)) {
4 return error;
5 }
6
7 // Error categorization
8 const severity = categorizeError(error);
9
10 // Different handling based on severity
11 switch (severity) {
12 case 'critical':
13 sendToSlack(error);
14 sendToSentry(error);
15 break;
16 case 'warning':
17 sendToSentry(error);
18 break;
19 case 'info':
20 logToFile(error);
21 break;
22 }
23
24 // Enrich error with additional context
25 return {
26 ...error,
27 context: {
28 ...error.context,
29 severity,
30 environment: process.env.NODE_ENV,
31 version: process.env.APP_VERSION
32 }
33 };
34}
performance
Advanced performance optimization settings for high-throughput scenarios.
1performance: {
2 errorCreation: {
3 // Enable object pooling to reduce GC pressure
4 objectPooling: true,
5 poolSize: 200, // Number of pre-allocated errors
6
7 // Defer expensive computations
8 lazyStackTrace: true,
9 lazySourceLocation: true
10 },
11
12 contextCapture: {
13 // Limit context object depth
14 maxDepth: 3,
15 maxProperties: 50,
16
17 // Exclude sensitive fields
18 excludePatterns: ['password', 'token', 'secret', 'apiKey']
19 },
20
21 memoryManagement: {
22 // Limit error history
23 maxErrorsInMemory: 1000,
24 errorTTL: 60000 // 1 minute
25 }
26}
Configuration API
For advanced use cases, you can use the configuration API directly to customize tryError behavior.
configure()
Configure global settings for tryError behavior.
1import { configure, TryErrorConfig } from '@try-error/core';
2
3// Configure global settings
4configure({
5 // Enable/disable stack trace capture
6 captureStackTrace: true,
7
8 // Maximum stack trace depth
9 stackTraceLimit: 10,
10
11 // Include source location in errors
12 includeSource: true,
13
14 // Default error type for untyped errors
15 defaultErrorType: 'Error',
16
17 // Enable development mode features
18 developmentMode: process.env.NODE_ENV === 'development',
19
20 // Custom error serialization
21 serializer: (error) => ({
22 type: error.type,
23 message: error.message,
24 timestamp: error.timestamp,
25 ...(process.env.NODE_ENV === 'development' && {
26 stack: error.stack,
27 context: error.context
28 })
29 }),
30
31 // Error transformation hook
32 onError: (error) => {
33 // Log to monitoring service
34 if (process.env.NODE_ENV === 'production') {
35 logToMonitoring(error);
36 }
37 return error;
38 }
39});
40
41// Or use a preset
42configure('production'); // Uses ConfigPresets.production()
43configure('development'); // Uses ConfigPresets.development()
Configuration Presets
Pre-built configurations for common environments.
1import { ConfigPresets, configure } from '@try-error/core';
2
3// Use built-in presets
4configure(ConfigPresets.development()); // Full debugging features
5configure(ConfigPresets.production()); // Performance optimized (no console)
6configure(ConfigPresets.test()); // Test-friendly configuration
7configure(ConfigPresets.performance()); // Maximum performance with caching
8configure(ConfigPresets.minimal()); // Ultra-lightweight (<50% overhead)
9
10// Environment-specific presets
11configure(ConfigPresets.serverProduction()); // Server with logging integration
12configure(ConfigPresets.clientProduction()); // Client with error tracking
13configure(ConfigPresets.edge()); // Edge/serverless optimized
14configure(ConfigPresets.nextjs()); // Next.js with runtime detection 🎯
15
16// Customize presets
17const customConfig = {
18 ...ConfigPresets.production(),
19 onError: (error) => sendToMyService(error)
20};
21configure(customConfig);
22
23// Helper for error service integration
24import { withErrorService } from '@try-error/core';
25
26configure(withErrorService((error) => {
27 Sentry.captureException(error);
28}));
Scoped Configuration
Create isolated configurations that don't affect global state.
1import { createScope } from '@try-error/core';
2
3// Create a scoped configuration
4const { config, createError } = createScope({
5 captureStackTrace: false,
6 defaultErrorType: 'CustomError',
7 onError: (error) => {
8 console.log('Scoped error:', error.message);
9 return error;
10 }
11});
12
13// Use scoped error creation
14const error = await createError({
15 message: 'This uses scoped config',
16 context: { scope: 'isolated' }
17});
18
19// Global config remains unchanged
20const globalError = createTryError('GlobalError', 'Uses global config');
Preset Details
- • Stack traces: Disabled
- • Console logging: None (changed in v1.0)
- • Source location: Included
- • Best for: Generic production environments
- • Stack traces: Disabled
- • Console logging: None
- • Source location: Included (for logs)
- • Best for: Node.js servers, API backends
- • Integrate with: Winston, Pino, CloudWatch
- • Stack traces: Disabled
- • Console logging: None
- • Source location: Included
- • Custom serializer: Removes sensitive data
- • Best for: Browser apps, React, Vue
- • Integrate with: Sentry, LogRocket, Bugsnag
- • Stack traces: Disabled
- • Source location: Disabled (size optimization)
- • Minimal mode: Enabled
- • Best for: Cloudflare Workers, Vercel Edge, Deno Deploy
- • Overhead: <100% on error paths
- • Stack traces: Disabled
- • Source location: Disabled
- • Timestamp: Disabled
- • Context: Disabled
- • Overhead: <50% on error paths
- • Best for: Hot code paths, high-frequency operations
- • Runtime detection: Enabled
- • Stack traces: Dev only
- • Source location: Included
- • Automatic environment handlers for server/client/edge
- • Best for: Next.js 13+ App Router & Pages Router
- • Solves: Global config conflicts in isomorphic apps
Next.js Configuration Guide
1import { setupNextJs } from '@try-error/core/setup';
2
3// This runs on both server and client
4// tryError automatically detects the runtime environment for each error
5setupNextJs();
6
7export default function RootLayout({
8 children,
9}: {
10 children: React.ReactNode;
11}) {
12 return (
13 <html lang="en">
14 <body>{children}</body>
15 </html>
16 );
17}
1import { setupNextJs } from '@try-error/core/setup';
2import * as Sentry from '@sentry/nextjs';
3import { logger } from '@/lib/logger';
4
5// Configure with custom environment handlers
6setupNextJs({
7 // Base configuration (applies to all environments)
8 includeSource: true,
9 captureStackTrace: process.env.NODE_ENV === 'development',
10
11 // Environment-specific handlers (called based on runtime detection)
12 environmentHandlers: {
13 server: (error) => {
14 // Server-side: Log to your logging service
15 if (process.env.NODE_ENV === 'production') {
16 logger.error({
17 type: error.type,
18 message: error.message,
19 source: error.source,
20 timestamp: error.timestamp,
21 context: error.context,
22 });
23 }
24 return error;
25 },
26
27 client: (error) => {
28 // Client-side: Send to error tracking
29 if (process.env.NODE_ENV === 'production') {
30 Sentry.captureException(error);
31 // No console output in production
32 }
33 return error;
34 },
35
36 edge: (error) => {
37 // Edge runtime: Minimal logging
38 console.log(JSON.stringify({
39 type: error.type,
40 message: error.message,
41 timestamp: error.timestamp,
42 runtime: 'edge'
43 }));
44 return error;
45 }
46 }
47});
1'use server';
2
3import { tryAsync, isTryError } from '@try-error/core';
4import { revalidatePath } from 'next/cache';
5
6export async function updateUser(userId: string, data: UpdateUserData) {
7 const result = await tryAsync(async () => {
8 // Validate input
9 const validation = validateUserData(data);
10 if (!validation.valid) {
11 throw createError({
12 type: 'ValidationError',
13 message: 'Invalid user data',
14 context: { errors: validation.errors }
15 });
16 }
17
18 // Update in database
19 const user = await db.user.update({
20 where: { id: userId },
21 data: data
22 });
23
24 revalidatePath(`/users/${userId}`);
25 return user;
26 });
27
28 if (isTryError(result)) {
29 // Server actions can't throw serializable errors
30 // Return error as data
31 return {
32 success: false,
33 error: {
34 type: result.type,
35 message: result.message,
36 // Don't send full error details to client
37 }
38 };
39 }
40
41 return { success: true, data: result };
42}
1import { tryAsync, isTryError } from '@try-error/core';
2import { NextRequest, NextResponse } from 'next/server';
3
4export async function GET(request: NextRequest) {
5 const result = await tryAsync(async () => {
6 const users = await fetchUsers();
7 return users;
8 });
9
10 if (isTryError(result)) {
11 // Log server-side error (will use server config)
12 console.error('API Error:', result);
13
14 return NextResponse.json(
15 { error: 'Failed to fetch users' },
16 { status: 500 }
17 );
18 }
19
20 return NextResponse.json(result);
21}
1import { setupNextJs } from '@try-error/core/setup';
2import * as Sentry from '@sentry/nextjs';
3import { Logger } from 'winston';
4
5// Your server logger
6const serverLogger = new Logger({
7 // ... winston config
8});
9
10export function initializeTryError() {
11 setupNextJs({
12 server: {
13 captureStackTrace: process.env.NODE_ENV === 'development',
14 onError: (error) => {
15 // Server: Use Winston or similar
16 serverLogger.error('Application error', {
17 error: {
18 type: error.type,
19 message: error.message,
20 source: error.source,
21 context: error.context,
22 stack: error.stack,
23 },
24 timestamp: new Date().toISOString(),
25 });
26
27 // Also send to Sentry on server
28 Sentry.captureException(error);
29 return error;
30 }
31 },
32
33 client: {
34 captureStackTrace: false,
35 skipContext: true, // Don't expose server context to client
36 onError: (error) => {
37 // Client: Send to Sentry
38 Sentry.captureException(error, {
39 tags: {
40 errorType: error.type,
41 source: 'client',
42 },
43 extra: {
44 timestamp: error.timestamp,
45 }
46 });
47
48 // In development, log to console
49 if (process.env.NODE_ENV === 'development') {
50 console.error('[Client Error]', error);
51 }
52
53 return error;
54 }
55 }
56 });
57}
1. Install Sentry
pnpm add @sentry/nextjs
# or for other frameworks:
pnpm add @sentry/node @sentry/react
2. Initialize Sentry
1import * as Sentry from '@sentry/nextjs';
2
3Sentry.init({
4 dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
5 environment: process.env.NODE_ENV,
6 integrations: [
7 Sentry.replayIntegration(),
8 Sentry.feedbackIntegration({
9 colorScheme: 'auto',
10 }),
11 ],
12 tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0,
13 replaysSessionSampleRate: 0.1,
14 replaysOnErrorSampleRate: 1.0,
15});
3. Configure tryError with Sentry
1import { configure } from '@try-error/core';
2import * as Sentry from '@sentry/nextjs';
3
4// Configure tryError to send all errors to Sentry
5configure({
6 onError: (error) => {
7 // Capture in Sentry with additional context
8 Sentry.captureException(error, {
9 tags: {
10 errorType: error.type,
11 environment: process.env.NODE_ENV,
12 version: process.env.NEXT_PUBLIC_APP_VERSION,
13 },
14 contexts: {
15 tryError: {
16 type: error.type,
17 source: error.source,
18 timestamp: error.timestamp,
19 },
20 },
21 extra: error.context,
22 });
23
24 // Also set user context if available
25 if (error.context?.userId) {
26 Sentry.setUser({
27 id: error.context.userId,
28 email: error.context.userEmail,
29 });
30 }
31
32 return error;
33 },
34
35 // Customize serialization for Sentry
36 serializer: (error) => ({
37 type: error.type,
38 message: error.message,
39 timestamp: error.timestamp,
40 // Include stack traces in production for Sentry
41 stack: error.stack,
42 source: error.source,
43 context: error.context,
44 }),
45});
4. Enhanced Error Creation for Sentry
1import { createTryError } from '@try-error/core';
2import * as Sentry from '@sentry/nextjs';
3
4// Create errors with Sentry-friendly context
5export async function processPayment(userId: string, amount: number) {
6 // Add breadcrumb for Sentry
7 Sentry.addBreadcrumb({
8 category: 'payment',
9 message: 'Processing payment',
10 level: 'info',
11 data: { userId, amount },
12 });
13
14 const result = await tryAsync(async () => {
15 const payment = await paymentAPI.process({ userId, amount });
16
17 if (!payment.success) {
18 // Create error with rich context for Sentry
19 throw createTryError('PaymentError', payment.error.message, {
20 userId,
21 amount,
22 paymentId: payment.id,
23 errorCode: payment.error.code,
24 // This will be captured in Sentry's extra data
25 paymentProvider: payment.provider,
26 attemptNumber: payment.attemptNumber,
27 });
28 }
29
30 return payment;
31 });
32
33 if (isTryError(result)) {
34 // Add specific Sentry context for payment errors
35 Sentry.withScope((scope) => {
36 scope.setTag('payment.failed', true);
37 scope.setContext('payment', {
38 userId,
39 amount,
40 error: result.message,
41 });
42 scope.setLevel('error');
43 });
44 }
45
46 return result;
47}
1. Install Vercel Analytics
pnpm add @vercel/analytics
2. Setup Analytics with Error Tracking
1import { Analytics } from '@vercel/analytics/react';
2import { configure } from '@try-error/core';
3import { track } from '@vercel/analytics';
4
5// Configure tryError to track errors as custom events
6configure({
7 onError: (error) => {
8 // Track error occurrence in Vercel Analytics
9 track('error_occurred', {
10 errorType: error.type,
11 errorMessage: error.message,
12 source: error.source?.file || 'unknown',
13 // Don't send sensitive data to analytics
14 path: typeof window !== 'undefined' ? window.location.pathname : 'server',
15 });
16
17 // Track specific error types differently
18 if (error.type === 'ValidationError') {
19 track('validation_error', {
20 fields: error.context?.validationErrors?.length || 0,
21 form: error.context?.formName,
22 });
23 } else if (error.type === 'APIError') {
24 track('api_error', {
25 endpoint: error.context?.endpoint,
26 statusCode: error.context?.statusCode,
27 });
28 }
29
30 return error;
31 },
32});
33
34export default function RootLayout({ children }) {
35 return (
36 <html lang="en">
37 <body>
38 {children}
39 <Analytics
40 mode={process.env.NODE_ENV === 'production' ? 'production' : 'development'}
41 beforeSend={(event) => {
42 // Redact sensitive paths from analytics
43 if (event.url.includes('/admin') || event.url.includes('/api/internal')) {
44 return null;
45 }
46 return event;
47 }}
48 />
49 </body>
50 </html>
51 );
52}
3. Track Error Recovery and User Actions
1import { track } from '@vercel/analytics';
2import { tryAsync, isTryError } from '@try-error/core';
3
4export function PaymentForm() {
5 const [retryCount, setRetryCount] = useState(0);
6
7 const handleSubmit = async (formData) => {
8 const result = await tryAsync(() => processPayment(formData));
9
10 if (isTryError(result)) {
11 // Track error with retry context
12 track('payment_error', {
13 errorType: result.type,
14 retryCount,
15 amount: formData.amount,
16 // Track recovery actions
17 userAction: retryCount > 0 ? 'retry' : 'initial_attempt',
18 });
19
20 if (result.type === 'NetworkError' && retryCount < 3) {
21 // Track retry attempt
22 track('error_retry_attempted', {
23 errorType: result.type,
24 attemptNumber: retryCount + 1,
25 });
26 setRetryCount(retryCount + 1);
27 }
28 } else {
29 // Track successful recovery
30 if (retryCount > 0) {
31 track('error_recovered', {
32 errorType: 'PaymentError',
33 retriesNeeded: retryCount,
34 });
35 }
36
37 // Track successful payment
38 track('payment_success', {
39 amount: formData.amount,
40 retriesNeeded: retryCount,
41 });
42 }
43 };
44
45 return (
46 // Your form JSX
47 );
48}
4. Error Analytics Dashboard Integration
1import { configure } from '@try-error/core';
2import { track } from '@vercel/analytics';
3
4// Track error metrics for analytics dashboard
5configure({
6 onError: (error) => {
7 const errorMetrics = {
8 // Basic error info
9 type: error.type,
10 severity: getSeverityLevel(error),
11
12 // Performance impact
13 occurredAt: new Date().toISOString(),
14 environment: process.env.NODE_ENV,
15
16 // User impact
17 userId: error.context?.userId || 'anonymous',
18 sessionId: error.context?.sessionId,
19
20 // Error categorization for analytics
21 category: categorizeError(error),
22 isRecoverable: isRecoverableError(error),
23
24 // Feature flags or A/B test context
25 featureFlags: error.context?.featureFlags,
26 experimentId: error.context?.experimentId,
27 };
28
29 // Send to Vercel Analytics
30 track('error_metrics', errorMetrics);
31
32 // Track critical errors separately
33 if (errorMetrics.severity === 'critical') {
34 track('critical_error', {
35 type: error.type,
36 message: error.message,
37 impactedFeature: error.context?.feature,
38 });
39 }
40
41 return error;
42 },
43});
44
45// Helper functions for error categorization
46function getSeverityLevel(error) {
47 const criticalTypes = ['DatabaseError', 'AuthenticationError', 'PaymentError'];
48 const warningTypes = ['ValidationError', 'RateLimitError'];
49
50 if (criticalTypes.includes(error.type)) return 'critical';
51 if (warningTypes.includes(error.type)) return 'warning';
52 return 'info';
53}
54
55function categorizeError(error) {
56 const categoryMap = {
57 ValidationError: 'user_input',
58 NetworkError: 'infrastructure',
59 DatabaseError: 'infrastructure',
60 AuthenticationError: 'security',
61 AuthorizationError: 'security',
62 PaymentError: 'business_critical',
63 RateLimitError: 'performance',
64 };
65
66 return categoryMap[error.type] || 'other';
67}
68
69function isRecoverableError(error) {
70 const recoverableTypes = ['NetworkError', 'RateLimitError', 'TimeoutError'];
71 return recoverableTypes.includes(error.type);
72}
1import { configure } from '@try-error/core';
2import * as Sentry from '@sentry/nextjs';
3import { track } from '@vercel/analytics';
4
5export function setupErrorMonitoring() {
6 configure({
7 // Capture stack traces only in development
8 captureStackTrace: process.env.NODE_ENV === 'development',
9
10 // Production-optimized settings
11 skipTimestamp: process.env.NODE_ENV === 'production',
12 skipContext: process.env.NODE_ENV === 'production',
13
14 onError: (error) => {
15 // 1. Send to Sentry for debugging
16 Sentry.captureException(error, {
17 tags: {
18 errorType: error.type,
19 environment: process.env.NODE_ENV,
20 version: process.env.NEXT_PUBLIC_APP_VERSION,
21 },
22 contexts: {
23 tryError: {
24 type: error.type,
25 source: error.source,
26 timestamp: error.timestamp,
27 },
28 },
29 extra: error.context,
30 });
31
32 // 2. Track in Vercel Analytics for metrics
33 track('error', {
34 type: error.type,
35 category: categorizeError(error),
36 severity: getSeverityLevel(error),
37 path: typeof window !== 'undefined' ? window.location.pathname : 'server',
38 });
39
40 // 3. Log to console in development
41 if (process.env.NODE_ENV === 'development') {
42 console.error(`[${error.type}]`, error.message, error);
43 }
44
45 // 4. Send critical errors to PagerDuty or similar
46 if (isCriticalError(error)) {
47 notifyOncall(error);
48 }
49
50 return error;
51 },
52
53 // Custom serialization for production
54 serializer: (error) => {
55 // Full details for Sentry
56 if (process.env.NODE_ENV === 'development') {
57 return error; // Return full error object
58 }
59
60 // Minimal details for production client
61 return {
62 type: error.type,
63 message: error.message,
64 timestamp: error.timestamp,
65 // Only include non-sensitive context
66 context: {
67 url: error.context?.url,
68 statusCode: error.context?.statusCode,
69 },
70 };
71 },
72 });
73
74 // Set up Sentry user context
75 if (typeof window !== 'undefined') {
76 const userId = getUserId(); // Your user ID logic
77 if (userId) {
78 Sentry.setUser({ id: userId });
79 }
80 }
81}
82
83// Initialize on app start
84setupErrorMonitoring();
Runtime Detection for Isomorphic Apps
Traditional error libraries use global configuration that gets overwritten in isomorphic apps. tryError's runtime detection ensures each error uses the correct handler based on where it's thrown.
1// Server starts
2configure({ onError: serverHandler });
3
4// Client loads (overwrites!)
5configure({ onError: clientHandler });
6
7// Now server uses client config 🚨
1// Configure once with handlers
2configure({
3 runtimeDetection: true,
4 environmentHandlers: {
5 server: serverHandler,
6 client: clientHandler
7 }
8});
9
10// Each error uses correct handler
1// When an error is created, tryError detects:
2
3// Edge Runtime
4if (globalThis.EdgeRuntime || process.env.NEXT_RUNTIME === 'edge') {
5 return 'edge';
6}
7
8// Server-side
9if (typeof window === 'undefined' && process.versions?.node) {
10 return 'server';
11}
12
13// Client-side
14return 'client';
Configuration Options
Complete reference for all configuration options available in tryError.
TryErrorConfig Interface
1interface TryErrorConfig {
2 /**
3 * Whether to capture stack traces (expensive operation)
4 * @default true in development, false in production
5 */
6 captureStackTrace?: boolean;
7
8 /**
9 * Maximum stack trace depth to capture
10 * @default 10
11 */
12 stackTraceLimit?: number;
13
14 /**
15 * Include source location in errors
16 * @default true
17 */
18 includeSource?: boolean;
19
20 /**
21 * Enable minimal error mode for ultra-lightweight errors
22 * Bypasses all expensive operations like stack trace capture
23 * @default false
24 */
25 minimalErrors?: boolean;
26
27 /**
28 * Skip timestamp generation (Date.now() calls)
29 * Useful for performance-critical paths
30 * @default false
31 */
32 skipTimestamp?: boolean;
33
34 /**
35 * Skip context processing
36 * Prevents deep cloning or processing of context objects
37 * @default false
38 */
39 skipContext?: boolean;
40
41 /**
42 * Default error type for untyped errors
43 * @default "Error"
44 */
45 defaultErrorType?: string;
46
47 /**
48 * Enable development mode features (verbose logging, etc.)
49 * @default false
50 */
51 developmentMode?: boolean;
52
53 /**
54 * Custom error serialization function
55 */
56 serializer?: (error: TryError) => Record<string, unknown>;
57
58 /**
59 * Global error transformation hook
60 */
61 onError?: (error: TryError) => TryError;
62}
Performance Configuration
Advanced performance optimization settings for high-throughput applications.
1interface PerformanceConfig {
2 /**
3 * Error creation optimization settings
4 */
5 errorCreation?: {
6 /**
7 * Cache error constructors for reuse
8 * @default false
9 */
10 cacheConstructors?: boolean;
11
12 /**
13 * Only capture stack trace when accessed (lazy)
14 * @default false
15 */
16 lazyStackTrace?: boolean;
17
18 /**
19 * Enable experimental object pooling
20 * @default false
21 */
22 objectPooling?: boolean;
23
24 /**
25 * Object pool size when pooling is enabled
26 * @default 50
27 */
28 poolSize?: number;
29 };
30
31 /**
32 * Context capture optimization settings
33 */
34 contextCapture?: {
35 /**
36 * Maximum context size in bytes
37 * @default 10240 (10KB)
38 */
39 maxContextSize?: number;
40
41 /**
42 * Whether to deep clone context objects
43 * @default true
44 */
45 deepClone?: boolean;
46
47 /**
48 * Timeout for async context capture in milliseconds
49 * @default 100
50 */
51 timeout?: number;
52 };
53
54 /**
55 * Memory management settings
56 */
57 memory?: {
58 /**
59 * Maximum number of errors to keep in history
60 * @default 100
61 */
62 maxErrorHistory?: number;
63
64 /**
65 * Use weak references for large contexts
66 * @default false
67 */
68 useWeakRefs?: boolean;
69
70 /**
71 * Provide garbage collection hints
72 * @default false
73 */
74 gcHints?: boolean;
75 };
76}
Environment-Specific Configuration
Configure different behaviors for development, testing, and production environments.
Development Configuration
1// config/development.ts
2import { configure } from '@try-error/core';
3
4configure({
5 captureStackTrace: true,
6 stackTraceLimit: 50, // More detailed stack traces
7 includeSource: true,
8 developmentMode: true,
9
10 serializer: (error) => ({
11 type: error.type,
12 message: error.message,
13 stack: error.stack,
14 source: error.source,
15 context: error.context,
16 timestamp: error.timestamp,
17 cause: error.cause
18 }),
19
20 // Global error handling
21 onError: (error) => {
22 // Detailed console logging in development
23 console.group(`🚨 TryError: ${error.type}`);
24 console.error('Message:', error.message);
25 console.error('Source:', error.source);
26 console.error('Context:', error.context);
27 console.error('Stack:', error.stack);
28 console.groupEnd();
29 return error;
30 }
31});
Production Configuration
1// config/production.ts
2import { configure } from '@try-error/core';
3
4configure({
5 captureStackTrace: false, // Disable for performance
6 stackTraceLimit: 5,
7 includeSource: false, // Don't expose source paths
8 developmentMode: false,
9
10 serializer: (error) => ({
11 type: error.type,
12 message: error.message,
13 timestamp: error.timestamp,
14 // Don't include sensitive information
15 }),
16
17 onError: (error) => {
18 // Send to monitoring service
19 sendToSentry(error);
20 sendToDatadog(error);
21
22 // Log minimal information
23 console.error(`Error: ${error.type} - ${error.message}`);
24 return error;
25 }
26});
Testing Configuration
1// config/testing.ts
2import { configure } from '@try-error/core';
3
4// Collect errors for test assertions
5const testErrors: TryError[] = [];
6
7configure({
8 captureStackTrace: true,
9 stackTraceLimit: 10,
10 includeSource: true,
11 developmentMode: true,
12
13 serializer: (error) => ({
14 type: error.type,
15 message: error.message,
16 context: error.context,
17 source: error.source,
18 stack: error.stack
19 }),
20
21 onError: (error) => {
22 testErrors.push(error);
23 return error;
24 }
25});
26
27// Helper for tests
28export function getTestErrors(): TryError[] {
29 return [...testErrors];
30}
31
32export function clearTestErrors(): void {
33 testErrors.length = 0;
34}
Performance Optimization
Advanced configuration for high-performance applications.
High-Performance Configuration
1import { configure, ConfigPresets } from '@try-error/core';
2
3// Use the performance preset
4configure(ConfigPresets.performance());
5
6// Or configure manually
7configure({
8 captureStackTrace: false,
9 stackTraceLimit: 0,
10 includeSource: false,
11 developmentMode: false,
12
13 // Performance optimizations
14 performance: {
15 errorCreation: {
16 cacheConstructors: true,
17 lazyStackTrace: true,
18 objectPooling: true,
19 poolSize: 100
20 },
21 contextCapture: {
22 maxContextSize: 1024 * 5, // 5KB limit
23 deepClone: false,
24 timeout: 50
25 },
26 memory: {
27 maxErrorHistory: 50,
28 useWeakRefs: true,
29 gcHints: true
30 }
31 }
32});
Performance Monitoring
1import { Performance } from '@try-error/core';
2
3// Measure error creation performance
4const metrics = Performance.measureErrorCreation(1000);
5console.log(`Average error creation time: ${metrics.averageTime}ms`);
6
7// Monitor memory usage (Node.js only)
8const memoryUsage = Performance.getMemoryUsage();
9if (memoryUsage) {
10 console.log('Memory usage:', memoryUsage);
11}
12
13// Set up performance monitoring
14configure({
15 onError: (error) => {
16 // Track error creation time
17 const creationTime = Date.now() - error.timestamp;
18 if (creationTime > 10) { // Log slow error creation
19 console.warn(`Slow error creation: ${creationTime}ms for ${error.type}`);
20 }
21 return error;
22 }
23});
Ultra-Performance Configuration
For performance-critical applications where even minimal overhead matters.
🚀 Performance Impact Overview
Success Path Overhead
- • Default config: ~3-5% overhead ✅
- • Production config: ~2-3% overhead ✅
- • Minimal config: <1% overhead 🚀
Error Path Overhead
- • Default config: ~100-120% overhead ❌
- • Production config: ~40% overhead ⚠️
- • Minimal config: ~20% overhead ✅
Note: Error path overhead is less critical since errors should be exceptional. Choose configuration based on your specific needs.
Minimal Configuration Preset
The minimal preset achieves <50% error overhead by disabling all expensive operations.
1import { configure, ConfigPresets } from '@try-error/core';
2
3// Use the minimal preset for <50% overhead
4configure(ConfigPresets.minimal());
5
6// What this does internally:
7configure({
8 captureStackTrace: false, // No stack trace capture
9 stackTraceLimit: 0, // Zero stack frames
10 includeSource: false, // No source location
11 developmentMode: false, // Production mode
12 minimalErrors: true, // Bypass expensive operations
13 skipTimestamp: true, // No Date.now() calls
14 skipContext: true // No context processing
15});
16
17// Result: Ultra-lightweight errors
18const error = trySync(() => JSON.parse("invalid"));
19// error = {
20// type: "SyntaxError",
21// message: "Unexpected token i in JSON",
22// source: "minimal",
23// timestamp: 0,
24// stack: undefined,
25// context: undefined
26// }
Direct Minimal Error API
For the absolute lowest overhead, use the direct minimal error creation API.
1import { createMinimalError } from '@try-error/core';
2
3// Bypass all processing - near-zero overhead
4const error = createMinimalError(
5 "NetworkError",
6 "Request failed"
7);
8
9// With optional context (still lightweight)
10const errorWithContext = createMinimalError(
11 "ValidationError",
12 "Invalid email format",
13 { email: userInput }
14);
15
16// Use in performance-critical loops
17for (let i = 0; i < 1000000; i++) {
18 const result = data[i];
19 if (!isValid(result)) {
20 errors.push(createMinimalError(
21 "DataError",
22 "Invalid data at index " + i
23 ));
24 }
25}
Performance Comparison
Real-world benchmark results for different configurations (1M operations).
1// Benchmark: JSON parsing with errors (1M iterations)
2
3// Native try/catch baseline
4try {
5 JSON.parse("invalid");
6} catch (e) {}
7// Time: 4,708ms
8
9// Default tryError configuration
10const result1 = trySync(() => JSON.parse("invalid"));
11// Time: 85,734ms (1720% overhead) ❌
12
13// Production configuration
14configure({ captureStackTrace: false, includeSource: false });
15const result2 = trySync(() => JSON.parse("invalid"));
16// Time: 23,544ms (400% overhead) ⚠️
17
18// Minimal configuration
19configure(ConfigPresets.minimal());
20const result3 = trySync(() => JSON.parse("invalid"));
21// Time: 7,062ms (50% overhead) ✅
22
23// Direct minimal API
24const error = createMinimalError("ParseError", "Invalid JSON");
25// Time: 4,944ms (5% overhead) 🚀
When to Use Each Configuration
Default Configuration
Use when you need full debugging capabilities and error overhead is not a concern.
- ✅ Development environments
- ✅ Applications with infrequent errors
- ✅ When debugging is more important than performance
Production Configuration
Balanced approach for production applications.
- ✅ Standard web applications
- ✅ APIs with moderate error rates
- ✅ When you need some error context
Minimal Configuration
Maximum performance for error-heavy operations.
- ✅ High-frequency parsing operations
- ✅ Data validation loops
- ✅ Performance-critical paths
- ✅ When errors are expected and frequent
Direct Minimal API
Absolute minimum overhead for the most critical paths.
- ✅ Tight loops with millions of iterations
- ✅ Real-time systems
- ✅ When every microsecond counts
Gradual Performance Optimization
Start with defaults and optimize based on profiling results.
1// Step 1: Start with defaults in development
2import { trySync } from '@try-error/core';
3
4// Step 2: Profile and identify bottlenecks
5if (process.env.NODE_ENV === 'production') {
6 // Step 3: Apply production optimizations
7 configure({
8 captureStackTrace: false,
9 includeSource: false
10 });
11}
12
13// Step 4: For identified hot paths, use minimal config
14function processLargeDataset(data: unknown[]) {
15 // Temporarily switch to minimal for this operation
16 const previousConfig = getConfig();
17 configure(ConfigPresets.minimal());
18
19 const errors: TryError[] = [];
20 for (const item of data) {
21 const result = trySync(() => validateItem(item));
22 if (isTryError(result)) {
23 errors.push(result);
24 }
25 }
26
27 // Restore previous configuration
28 configure(previousConfig);
29 return errors;
30}
31
32// Step 5: For the most critical paths, use direct API
33function ultraFastValidation(items: string[]) {
34 return items
35 .map((item, i) => {
36 try {
37 return JSON.parse(item);
38 } catch {
39 return createMinimalError("ParseError", "Invalid at " + i);
40 }
41 })
42 .filter(isTryError);
43}
Configuration Best Practices
✅ Do
- • Use setup utilities for quick, optimized configuration
- • Configure tryError early in your application startup
- • Use environment-specific configurations
- • Disable stack traces in production for performance
- • Set up error monitoring and reporting
- • Use scoped configurations for isolated components
- • Test your error handling configuration
❌ Don't
- • Configure tryError multiple times in the same application
- • Include sensitive data in error contexts
- • Use development configuration in production
- • Ignore performance implications of stack trace capture
- • Set overly large context size limits
- • Forget to handle errors in your onError hook
Related Pages
Performance Guide
Detailed performance optimization strategies and implementation examples
View Performance Guide →