Error Handling System
Run ID: 69bca53177c0421c0bf497492026-03-29Development
PantheraHive BOS
BOS Dashboard

Workflow Execution Summary

The "Error Handling System" workflow (category: Development) has been executed for the generate step using the collab app.

Language Specified: JavaScript

Error Types Focus: Test Error Types

This output provides a comprehensive guide to designing and implementing a robust error handling system in JavaScript, with a specific focus on incorporating and testing "Test Error Types" to ensure system resilience and correctness.


1. Introduction to Robust JavaScript Error Handling

Effective error handling is crucial for building reliable and maintainable applications. It ensures that applications can gracefully recover from unexpected situations, provide meaningful feedback to users and developers, and prevent unhandled exceptions from crashing the application. In JavaScript, this involves a combination of synchronous and asynchronous error management, custom error types, and strategic testing.

This guide will cover the fundamental principles, common patterns, and best practices for creating a resilient error handling system in JavaScript, with a particular emphasis on how to define, implement, and rigorously test various error scenarios, including those categorized as "Test Error Types."


2. Core Error Handling Strategies in JavaScript

2.1. Synchronous Error Handling: try...catch...finally

The try...catch...finally statement is the cornerstone of synchronous error handling in JavaScript.

Actionable Detail: Always wrap potentially failing synchronous operations within try...catch blocks at appropriate boundaries (e.g., function entry points, I/O operations).

2.2. Asynchronous Error Handling

Asynchronous operations introduce complexities. Traditional try...catch doesn't directly work across asynchronous boundaries without specific patterns.

2.2.1. Promises

Promises have built-in error handling mechanisms:

Actionable Detail: Always chain a .catch() to the end of your Promise chains to prevent unhandled promise rejections.

2.2.2. async/await

async/await syntax, while making asynchronous code look synchronous, still requires try...catch for error handling. An await call can throw an error, which can then be caught by a surrounding try...catch block.

Actionable Detail: Wrap await calls in try...catch blocks within your async functions to handle potential rejections from awaited Promises.

2.3. Custom Error Classes

Native JavaScript errors (e.g., Error, TypeError, RangeError) are often insufficient to convey specific application-level issues. Custom error classes allow you to:

Actionable Detail: Define custom error classes for distinct application-specific failure modes (e.g., ValidationError, NetworkError, AuthenticationError, ResourceNotFoundError). Extend from Error to inherit standard error properties like name and stack.

2.4. Global Error Handlers

For unhandled exceptions that propagate up to the top level, global error handlers provide a last resort mechanism to log errors and prevent application crashes (in Node.js) or provide a fallback UI (in browsers).

Actionable Detail: Implement global error handlers to catch any errors that escape local try...catch blocks. These handlers should primarily log the error, potentially notify monitoring systems, and perform graceful shutdown/degradation if necessary, but should generally not attempt to recover from the error.


3. Implementing "Test Error Types"

"Test Error Types" refers to defining specific error conditions that are critical to test and verify your error handling system. This section details how to create and leverage these types of errors for robust testing.

3.1. Defining Custom Error Types for Testing Scenarios

Consider error types that represent common failure points or specific business logic violations. These can be used both in production code and for simulating errors in tests.

Structured Data: Example Custom Error Types

text • 3,705 chars
### 3.3. Assertions for Error Handling

Your tests should not only simulate errors but also verify that the error handling logic correctly:

*   **Catches the error**: The `catch` block is executed.
*   **Transforms the error**: The raw error is converted into a more meaningful custom error (e.g., a low-level DB error into a `ResourceNotFoundError`).
*   **Logs the error**: The error is passed to the logging mechanism with appropriate severity and context.
*   **Provides correct user feedback**: In UI contexts, the user sees an appropriate message.
*   **Returns correct HTTP status codes**: In API contexts, the server responds with the expected status code.

**Actionable Detail:** Use `expect(...).rejects.toThrow(...)` or `expect(() => {...}).toThrow(...)` for asserting thrown errors. Verify the error type using `toBeInstanceOf()` and check specific properties of the error object.

---

## 4. Best Practices and Recommendations

### 4.1. Centralized Error Processing

*   **Recommendation:** Create a central error handling middleware (for web frameworks like Express) or a utility function (`errorHandler.js`) that processes all caught errors. This function can log, format, and potentially send alerts.
*   **Actionable Detail:** Your centralized handler should differentiate between operational errors (predictable, handled, e.g., `ValidationError`) and programmer errors (unpredictable, unhandled, e.g., `ReferenceError`).

### 4.2. Consistent Logging

*   **Recommendation:** Use a dedicated logging library (e.g., Winston, Pino) with different log levels (debug, info, warn, error, fatal).
*   **Actionable Detail:** Always log errors with sufficient context (user ID, request ID, relevant input parameters, stack trace) to aid in debugging. Mask sensitive information.

### 4.3. User Feedback and Graceful Degradation

*   **Recommendation:** Distinguish between errors that can be shown to the user and internal errors.
*   **Actionable Detail:** For user-facing errors, provide clear, concise, and helpful messages. For internal errors, provide a generic message and log the details for developers. Implement fallback UIs or features when certain services are unavailable.

### 4.4. Idempotency and Retries

*   **Recommendation:** Design operations to be idempotent where possible, meaning performing them multiple times has the same effect as performing them once.
*   **Actionable Detail:** For transient errors (e.g., network issues, temporary service unavailability), implement retry mechanisms with exponential backoff.

### 4.5. Security Considerations

*   **Recommendation:** Never expose sensitive internal error details (stack traces, database connection strings, internal server paths) directly to clients.
*   **Actionable Detail:** Sanitize error messages before sending them to the client. Map internal errors to generic, safe error messages for external consumption.

### 4.6. Monitoring and Alerting

*   **Recommendation:** Integrate with application performance monitoring (APM) tools (e.g., Sentry, New Relic, Datadog) to track error rates and types.
*   **Actionable Detail:** Set up alerts for critical error thresholds or specific error types to proactively identify and address issues.

### 4.7. Error Boundary Components (React/UI Frameworks)

*   **Recommendation:** For UI applications, use error boundaries (if your framework supports them) to catch errors in child components and display a fallback UI, preventing the entire application from crashing.

---

## 5. Structured Data: Example Error Handling Flow

This example illustrates a common error handling flow in a Node.js Express application, incorporating custom errors and centralized handling.

Sandboxed live preview

6. Actionable Next Steps

  1. Review Existing Codebase: Identify areas where error handling is missing or inconsistent. Prioritize critical paths and external integrations.
  2. Define Custom Error Taxonomy: Based on your application's domain, create a clear set of custom error classes (like the "Test Error Types" examples) that represent distinct failure conditions.
  3. Implement Centralized Error Handling: Set up a global error handling middleware or utility to process all errors consistently (logging, formatting, sending responses).
  4. Integrate Logging: Configure a robust logging solution (e.g., Winston) to capture error details effectively.
  5. Develop Comprehensive Tests: Write unit and integration tests that specifically target error paths, using mocking and assertion techniques to verify correct error handling for each "Test Error Type."
  6. Set Up Monitoring and Alerting: Connect your application to an APM tool and configure alerts for critical error conditions.
  7. Document Error Handling Strategy: Create internal documentation outlining your application's error handling philosophy, custom error types, and how errors are logged and reported.

This comprehensive approach will significantly improve the stability, maintainability, and diagnostic capabilities of your JavaScript application.

Step 2: projectmanager

Workflow Execution Output: Error Handling System Documentation

Workflow Name: Error Handling System

Category: Development

Language: JavaScript

Error Types Handled (Example): Test Error Types

This document outlines a comprehensive and professional error handling system for JavaScript applications, designed for robustness, maintainability, and enhanced debugging capabilities. It incorporates best practices for both frontend and backend JavaScript environments, emphasizing custom error types, centralized handling, logging, and reporting.


1. Introduction

A robust error handling system is crucial for the stability, reliability, and user experience of any application. This system aims to:

  • Prevent Application Crashes: Gracefully manage unexpected errors to keep the application running.
  • Improve Debugging: Provide clear, actionable error messages and context for developers.
  • Enhance User Experience: Present user-friendly messages where appropriate, avoiding cryptic errors.
  • Enable Proactive Monitoring: Integrate with logging and reporting tools to identify and resolve issues quickly.
  • Standardize Error Responses: Ensure consistent error formats across the application's API or UI.

This documentation serves as a guide for understanding, implementing, and utilizing the error handling capabilities within your JavaScript projects.

2. Core Concepts

The error handling system is built upon several core concepts:

  • Custom Error Classes: Extending JavaScript's native Error object to create domain-specific error types. This allows for programmatic identification and handling of different error conditions.
  • Centralized Error Handling: A single point of entry for processing all errors, regardless of where they originate. This ensures consistent logging, reporting, and response generation.
  • Global Error Catchers: Mechanisms to catch unhandled exceptions and promise rejections at the application level, preventing crashes and ensuring all errors are processed.
  • Contextual Information: Attaching relevant data (e.g., user ID, request payload, specific parameters) to errors to aid in debugging.
  • Logging Integration: Seamlessly integrating with logging services (e.g., console, file, cloud log aggregators) to persist error details.
  • Reporting Integration: Connecting with error monitoring services (e.g., Sentry, Bugsnag) for real-time alerts and analytics.
  • Graceful Degradation: Designing the system to fail predictably and minimally impact the user experience when an error occurs.

3. System Architecture

The error handling system follows a layered architecture to ensure separation of concerns and modularity:

  1. Application Code: Where errors originate (e.g., validation failures, database errors, external API issues).
  2. Custom Error Classes: Domain-specific errors are instantiated here.
  3. Error Utility/Service: A central module responsible for catching, processing, logging, and reporting errors.
  4. Global Error Handlers: Catch-all mechanisms for unhandled exceptions (e.g., process.on('uncaughtException') in Node.js, window.onerror in browsers).
  5. Logging Service: For persistent storage of error details (e.g., console, Winston, Pino, CloudWatch).
  6. Reporting Service: For real-time alerts and error aggregation (e.g., Sentry, Bugsnag).
  7. Response Layer (API/UI): Formats and sends appropriate error responses to clients or displays user-friendly messages.

graph TD
    A[Application Code] --> B{throw new CustomError()};
    B --> C[try...catch Block];
    C --> D[Error Utility Service];
    A --> G[Unhandled Error];
    G --> H[Global Error Handlers];
    H --> D;
    D --> E[Logging Service];
    D --> F[Reporting Service];
    D --> I[API/UI Response Layer];

4. Key Components

4.1. Custom Error Classes

Custom error classes extend the native Error object, allowing for semantic error identification and structured data attachment.

Base Error Class (src/errors/BaseError.js)


class BaseError extends Error {
    constructor(message, context = {}, statusCode = 500, isOperational = true) {
        super(message);
        this.name = this.constructor.name;
        this.context = context; // Additional debugging context
        this.statusCode = statusCode; // HTTP status code for API responses
        this.isOperational = isOperational; // Flag for operational vs. programming errors
        Error.captureStackTrace(this, this.constructor); // Captures stack trace
    }

    // Static method to check if an error is an instance of BaseError or its derivatives
    static isInstance(error) {
        return error instanceof BaseError;
    }
}

export { BaseError };

Specific Error Types (e.g., for "Test Error Types") (src/errors/TestErrors.js)

We'll define specific error types related to "Test Error Types" to illustrate how to categorize errors programmatically.


import { BaseError } from './BaseError';

/**
 * Base class for all test-related errors.
 */
class TestError extends BaseError {
    constructor(message, context = {}, statusCode = 500, isOperational = true) {
        super(message, context, statusCode, isOperational);
        this.errorCategory = 'TEST_ERROR'; // Custom category flag
    }
}

/**
 * Represents a validation failure during a test operation.
 */
class TestValidationError extends TestError {
    constructor(message = 'Test validation failed.', validationDetails = [], context = {}) {
        super(message, { ...context, validationDetails }, 400, true); // 400 Bad Request
        this.name = 'TestValidationError';
        this.validationDetails = validationDetails; // Specific details about validation failures
    }
}

/**
 * Represents an error related to test configuration.
 */
class TestConfigurationError extends TestError {
    constructor(message = 'Invalid test configuration.', configKey, context = {}) {
        super(message, { ...context, configKey }, 500, false); // 500 Internal Server Error, typically non-operational for user
        this.name = 'TestConfigurationError';
        this.configKey = configKey; // The problematic configuration key
    }
}

/**
 * Represents an error during the execution of a test (e.g., test runner issue).
 */
class TestExecutionError extends TestError {
    constructor(message = 'Test execution failed unexpectedly.', testId, context = {}) {
        super(message, { ...context, testId }, 500, false);
        this.name = 'TestExecutionError';
        this.testId = testId;
    }
}

export { TestError, TestValidationError, TestConfigurationError, TestExecutionError };

4.2. Central Error Handler/Utility

This service acts as the primary interface for processing errors.

(src/utils/errorHandler.js)


import { BaseError } from '../errors/BaseError';
import { logger } from './logger'; // Assuming a logger utility
import { errorReporter } from './errorReporter'; // Assuming an error reporting utility

class ErrorHandler {
    /**
     * Handles an error by logging it and optionally reporting it.
     * This is the primary method to call when catching an error.
     * @param {Error} error The error object.
     * @param {Object} [additionalContext={}] Additional context to log/report.
     */
    handleError(error, additionalContext = {}) {
        logger.error(`Error handled: ${error.message}`, {
            name: error.name,
            stack: error.stack,
            context: error.context,
            additionalContext,
            isOperational: error.isOperational,
            statusCode: error.statusCode,
        });

        // Report non-operational errors and critical operational errors to external services
        if (!error.isOperational || error.statusCode >= 500) {
            errorReporter.report(error, additionalContext);
        }

        // In a server environment, you might want to restart the process for critical non-operational errors
        // In a client environment, you might display a generic error message
        if (!error.isOperational) {
            console.error('CRITICAL NON-OPERATIONAL ERROR. Application might be in an unstable state.');
            // For server: process.exit(1); // Consider graceful shutdown before exiting
            // For client: display a fatal error screen and prompt refresh
        }
    }

    /**
     * Determines if an error is operational (expected and handled gracefully) or programming (unexpected).
     * @param {Error} error The error object.
     * @returns {boolean} True if the error is operational, false otherwise.
     */
    isOperationalError(error) {
        return error instanceof BaseError && error.isOperational;
    }

    /**
     * Formats an error for API responses.
     * @param {Error} error The error object.
     * @returns {{statusCode: number, message: string, code?: string, details?: any}} Formatted error object.
     */
    formatErrorForResponse(error) {
        if (this.isOperationalError(error)) {
            // Operational errors: provide user-friendly message and relevant details
            return {
                statusCode: error.statusCode,
                message: error.message,
                code: error.name,
                details: error.context,
            };
        } else {
            // Programming errors: hide internal details, provide generic message
            return {
                statusCode: 500,
                message: 'An unexpected error occurred.',
                code: 'INTERNAL_SERVER_ERROR',
                details: process.env.NODE_ENV === 'development' ? { stack: error.stack, name: error.name } : undefined,
            };
        }
    }
}

const errorHandler = new ErrorHandler();
export { errorHandler };

4.3. Global Unhandled Error Catchers

These mechanisms prevent the application from crashing due to uncaught exceptions or unhandled promise rejections.

Node.js (src/app.js or src/server.js)


import { errorHandler } from './utils/errorHandler';
import { logger } from './utils/logger'; // Make sure logger is initialized

// Catch unhandled synchronous exceptions
process.on('uncaughtException', (error) => {
    logger.fatal('Uncaught Exception! Shutting down...', { errorName: error.name, errorMessage: error.message, stack: error.stack });
    errorHandler.handleError(error, { type: 'uncaughtException' });
    // For critical non-operational errors, often best to exit and let a process manager restart
    if (!errorHandler.isOperationalError(error)) {
        process.exit(1);
    }
});

// Catch unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
    logger.fatal('Unhandled Rejection! Shutting down...', { reason, promise });
    // Rejections can be anything, wrap in an Error if it's not already one
    const error = (reason instanceof Error) ? reason : new Error(`Unhandled Rejection: ${reason}`);
    errorHandler.handleError(error, { type: 'unhandledRejection', promise });
    // For critical non-operational errors, often best to exit and let a process manager restart
    if (!errorHandler.isOperationalError(error)) {
        process.exit(1);
    }
});

// Example of integrating with an Express app (server-side)
// This middleware should be the LAST middleware added to your Express app
const errorMiddleware = (err, req, res, next) => {
    errorHandler.handleError(err, { requestUrl: req.originalUrl, method: req.method, body: req.body, user: req.user?.id });
    const formattedError = errorHandler.formatErrorForResponse(err);
    res.status(formattedError.statusCode).json({
        status: 'error',
        message: formattedError.message,
        code: formattedError.code,
        details: formattedError.details,
    });
};

export { errorMiddleware };

Browser (Client-side src/index.js or main entry file)


import { errorHandler } from './utils/errorHandler';

// Catch unhandled errors (syntax errors, runtime errors)
window.onerror = function (message, source, lineno, colno, error) {
    console.error('Window.onerror caught:', { message, source, lineno, colno, error });
    errorHandler.handleError(error || new Error(message), {
        type: 'window.onerror',
        source,
        lineno,
        colno
    });
    return true; // Prevent default browser error handling
};

// Catch unhandled promise rejections
window.addEventListener('unhandledrejection', (event) => {
    console.error('Unhandled Rejection caught:', event.reason);
    const error = (event.reason instanceof Error) ? event.reason : new Error(`Unhandled Rejection: ${event.reason}`);
    errorHandler.handleError(error, { type: 'unhandledRejection' });
    event.preventDefault(); // Prevent default browser handling
});

4.4. Logging Integration

A dedicated logging utility for structured and contextual logging.

(src/utils/logger.js)


// Example using console, but can be replaced with Winston, Pino, etc.
class Logger {
    log(level, message, metadata = {}) {
        const timestamp = new Date().toISOString();
        const logEntry = { timestamp, level, message, ...metadata };

        switch (level) {
            case 'debug':
                console.debug(JSON.stringify(logEntry));
                break;
            case 'info':
                console.info(JSON.stringify(logEntry));
                break;
            case 'warn':
                console.warn(JSON.stringify(logEntry));
                break;
            case 'error':
                console.error(JSON.stringify(logEntry));
                break;
            case 'fatal':
                console.error(JSON.stringify(logEntry));
                break;
            default:
                console.log(JSON.stringify(logEntry));
        }
    }

    debug(message, metadata) { this.log('debug', message, metadata); }
    info(message, metadata) { this.log('info', message, metadata); }
    warn(message, metadata) { this.log('warn', message, metadata); }
    error(message, metadata) { this.log('error', message, metadata); }
    fatal(message, metadata) { this.log('fatal', message, metadata); }
}

const logger = new Logger();
export { logger };

// In a real application, you might use a library like Winston or Pino
/*
import winston from 'winston';

const logger = winston.createLogger({
    level: process.env.LOG_LEVEL || 'info',
    format: winston.format.json(),
    transports: [
        new winston.transports.Console(),
        // new winston.transports.File({ filename: 'error.log', level: 'error' }),
        // new winston.transports.File({ filename: 'combined.log' }),
    ],
});

if (process.env.NODE_ENV !== 'production') {
    logger.add(new winston.transports.Console({
        format: winston.format.simple(),
    }));
}

export { logger };
*/

4.5. Reporting Integration

Connects with external error monitoring services.

(src/utils/errorReporter.js)


// Example using a placeholder, can be Sentry, Bugsnag, etc.
class ErrorReporter {
    constructor() {
        // Initialize your reporting service here (e.g., Sentry.init)
        if (process.env.SENTRY_DSN) {
            // import * as Sentry from '@sentry/node'; // or '@sentry/browser'
            // Sentry.init({ dsn: process.env.SENTRY_DSN });
            console.log('Sentry initialized (placeholder)');
            this.isInitialized = true;
        } else {
            console.warn('SENTRY_DSN not set. Error reporting disabled.');
            this.isInitialized = false;
        }
    }

    /**
     * Reports an error to an external service.
     * @param {Error} error The error object.
     * @param {Object} [context={}] Additional context to send with the report.
     */
    report(error, context = {}) {
        if (!this.isInitialized) {
            console.warn('Error reporter not initialized. Error not reported externally.');
            return;
        }

        console.log(`Reporting error to external service: ${error.name} - ${error.message}`, {
            error,
            context: {
                ...error.context,
                ...context,
                isOperational: error.isOperational,
                statusCode: error.statusCode,
            },
            stack: error.stack,
        });

        // Example for Sentry:
        // Sentry.withScope((scope) => {
        //     scope.setExtras({ ...error.context, ...context });
        //     if (error.statusCode) {
        //         scope.setTag('statusCode', error.statusCode);
        //     }
        //     if (error.errorCategory) {
        //         scope.setTag('category', error.errorCategory);
        //     }
        //     Sentry.captureException(error);
        // });
    }

    /**
     * Sets user context for error reporting (e.g., for Sentry).
     * @param {Object} user User information (id, email, username).
     */
    setUserContext(user) {
        if (this.isInitialized) {
            // Sentry.setUser({ id: user.id, email: user.email, username: user.username });
            console.log('User context set for reporting:', user);
        }
    }

    /**
     * Clears user context for error reporting.
     */
    clearUserContext() {
        if (this.isInitialized) {
            // Sentry.setUser(null);
            console.log('User context cleared for reporting.');
        }
    }
}

const errorReporter = new ErrorReporter();
export { errorReporter };

5. Usage Guide

5.1. Throwing Errors

Always throw custom errors for business logic failures.


import { TestValidationError, TestConfigurationError, TestExecutionError } from './errors/TestErrors';

function validateTestParameters(params) {
    if (!params || !params.testId) {
        throw new TestValidationError('Missing required test ID.', [{ field: 'testId', message: 'Test ID is required.' }], { userId: 'user123' });
    }
    if (params.testId.length < 5) {
        throw new TestValidationError('Test ID is too short.', [{ field: 'testId', message: 'Minimum length is 5.' }], { userId: 'user123' });
    }
    return true;
}

function loadTestConfig(configKey) {
    if (!process.env[configKey]) {
        throw new TestConfigurationError(`Environment variable for ${configKey} is not set.`, configKey, { service: 'TestRunner' });
    }
    return process.env[configKey];
}

async function runTest(testId) {
    // Simulate an external API call or complex logic that might fail
    try {
        const response = await fetch(`https://api.testservice.com/run/${testId}`);
        if (!response.ok) {
            const errorData = await response.json();
            throw new TestExecutionError(`Failed to execute test ${testId} via external service.`, testId, { apiResponse: errorData, httpStatus: response.status });
        }
        return await response.json();
    } catch (e) {
        // Catch network errors or parsing errors from fetch
        throw new TestExecutionError(`Network or parsing error during test execution for ${testId}.`, testId, { originalError: e.message });
    }
}

5.2. Catching and Handling Errors

Use try...catch blocks to catch errors and pass them to the central errorHandler.


import { errorHandler } from './utils/errorHandler';
import { TestValidationError, TestConfigurationError, TestExecutionError } from './errors/TestErrors';

async function processTestRequest(req, res) {
    const { testId, testParams } = req.body; // Example for an API request

    try {
        validateTestParameters(testParams); // Might throw TestValidationError
        const config = loadTestConfig('TEST_API_KEY'); // Might throw TestConfigurationError
        const testResult = await runTest(testId); // Might throw TestExecutionError

        res.status(200).json({ status: 'success', data: testResult });

    } catch (error) {
        // Pass all caught errors to the central handler
        errorHandler.handleError(error, { userId: req.user?.id, requestId: req.id });

        // For API responses, format the error appropriately
        const formattedError = errorHandler.formatErrorForResponse(error);
        res.status(formattedError.statusCode).json({
            status: 'error',
            message: formattedError.message,
            code: formattedError.code,
            details: formattedError.details,
        });

        // Example of specific handling for a TestValidationError (e.g., for UI feedback)
        if (error instanceof TestValidationError) {
            console.log(`UI should show specific validation errors: ${JSON.stringify(error.validationDetails)}`);
        }
    }
}

// Example usage
// Assuming req and res objects from an Express-like framework
// processTestRequest({ body: { testId: 'abc', testParams: {} } }, {}); // Will throw TestValidationError
// processTestRequest({ body: { testId: 'valid-id', testParams: { testId: 'valid-id' } } }, {}); // Will proceed if config and runTest don't fail

5.3. Example: Handling "Test Error Types"

This section demonstrates how the system categorizes and handles the custom Test Error Types defined earlier.

Error Differentiation and Response Mapping:

The errorHandler.formatErrorForResponse method, combined with the BaseError.isOperational flag and statusCode, provides a clear mechanism for differentiating errors and generating appropriate responses.

| Error Type | isOperational | statusCode | Typical API Response | Logging/Reporting |

| :---------------------- | :-------------- | :----------- | :--------------------------------------------------------------------------------- | :---------------------------------------------------- |

| TestValidationError | true | 400 | Specific validation messages, details with validationDetails. | Logged, not always reported externally (unless critical) |

| TestConfigurationError| false | 500 | Generic "Internal Server Error" (hides configKey in production), code: 'INTERNAL_SERVER_ERROR'. | Logged, always reported externally. |

| TestExecutionError | false | 500 | Generic "Internal Server Error" (hides originalError in production). | Logged, always reported externally. |

| Native Error | false | 500 | Generic "Internal Server Error". | Logged, always reported externally. |

Actionable Insight: By using custom error classes and the isOperational flag, you can distinguish between errors that are part of normal application flow (e.g., user input errors) and those that indicate a bug or system failure, allowing for different logging, reporting, and user feedback strategies.

6. Configuration

The error handling system's behavior can be configured via environment variables or a dedicated configuration file.


// Example configuration in a 'config.js' or '.env' file
// .env
// NODE_ENV=development
// LOG_LEVEL=debug
// SENTRY_DSN=https://examplepublickey@o0.ingest.sentry.io/0

// config.js
export const config = {
    env: process.env.NODE_ENV || 'development',
    logLevel: process.env.LOG_LEVEL || 'info',
    sentry: {
        dsn: process.env.SENTRY_DSN || null,
        enabled: !!process.env.SENTRY_DSN,
        // Other Sentry options
    },
    // Add other relevant configurations like error display messages
    errorMessages: {
        genericInternalError: 'An unexpected error occurred. Please try again later.',
        // ...
    }
};

Recommendations:

  • Use environment variables for sensitive data (e.g., Sentry DSN) and deployment-specific settings.
  • Centralize configuration to make it easy to manage and update.
  • Ensure different configurations for development, staging, and production environments.

7. Best Practices

  • Context is King: Always provide as much contextual information as possible when throwing or handling an error (e.g., user ID, request payload, relevant variable values).
  • Avoid Silent Failures: Never catch an error and do nothing with it. At a minimum, log it.
  • Distinguish Operational vs. Programming Errors: Use the isOperational flag to differentiate between expected, recoverable errors (e.g., validation) and unexpected bugs (e.g., null pointer).
  • Centralize Error Handling: Route all errors through a single errorHandler to ensure consistency.
  • User-Friendly Messages: For errors displayed to end-users, ensure messages are clear, concise, and actionable, avoiding technical jargon.
  • Log and Report Appropriately: Log all errors for auditing and debugging. Report only critical or non-operational errors to external monitoring services to avoid noise.
  • Test Error Paths: Write unit and integration tests specifically for error conditions to ensure your error handling works as expected.
  • Clean Up Resources: In finally blocks or error handlers, ensure resources (e.g., database connections, file handles) are properly closed or released.
  • Idempotency: Design operations to be idempotent where possible, so retrying after an error does not cause unintended side effects.

8. API Reference (Conceptual)

This section outlines the primary public methods of the errorHandler and errorReporter for quick reference.

errorHandler

  • errorHandler.handleError(error: Error, additionalContext?: object): The primary method to process any caught error. Logs the error, and conditionally reports it.
  • errorHandler.isOperationalError(error: Error): boolean: Checks if an error is an instance of BaseError and marked as operational.
  • errorHandler.formatErrorForResponse(error: Error): { statusCode: number, message: string, code?: string, details?: any }: Prepares an error object for sending as an API response, sanitizing sensitive details for non-operational errors.

errorReporter

  • errorReporter.report(error: Error, context?: object): Sends an error to the configured external error monitoring service (e.g., Sentry).
  • errorReporter.setUserContext(user: { id: string, email?: string, username?: string }): Associates user information with subsequent error reports.
  • errorReporter.clearUserContext(): Clears any previously set user context.

9. Maintenance and Troubleshooting

  • Regularly Review Logs: Monitor your application logs for recurring errors or spikes in specific error types.
  • Monitor Reporting Dashboards: Keep an eye on your Sentry/Bugsnag dashboards for new errors, trends, and performance issues.
  • Error Categorization: As your application grows, you may need to refine or add new custom error types to better categorize and handle specific scenarios.
  • Dependency Updates: Keep logging and reporting library dependencies updated to benefit from bug fixes and new features.
  • Test Environment Parity: Ensure your development and staging environments closely mimic
error_handling_system.txt
Download source file
Copy all content
Full output as text
Download ZIP
IDE-ready project ZIP
Copy share link
Permanent URL for this run
Get Embed Code
Embed this result on any website
Print / Save PDF
Use browser print dialog
\n\n\n"); var hasSrcMain=Object.keys(extracted).some(function(k){return k.indexOf("src/main")>=0;}); if(!hasSrcMain) zip.file(folder+"src/main."+ext,"import React from 'react'\nimport ReactDOM from 'react-dom/client'\nimport App from './App'\nimport './index.css'\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n \n \n \n)\n"); var hasSrcApp=Object.keys(extracted).some(function(k){return k==="src/App."+ext||k==="App."+ext;}); if(!hasSrcApp) zip.file(folder+"src/App."+ext,"import React from 'react'\nimport './App.css'\n\nfunction App(){\n return(\n
\n
\n

"+slugTitle(pn)+"

\n

Built with PantheraHive BOS

\n
\n
\n )\n}\nexport default App\n"); zip.file(folder+"src/index.css","*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:system-ui,-apple-system,sans-serif;background:#f0f2f5;color:#1a1a2e}\n.app{min-height:100vh;display:flex;flex-direction:column}\n.app-header{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:40px}\nh1{font-size:2.5rem;font-weight:700}\n"); zip.file(folder+"src/App.css",""); zip.file(folder+"src/components/.gitkeep",""); zip.file(folder+"src/pages/.gitkeep",""); zip.file(folder+"src/hooks/.gitkeep",""); Object.keys(extracted).forEach(function(p){ var fp=p.startsWith("src/")?p:"src/"+p; zip.file(folder+fp,extracted[p]); }); zip.file(folder+"README.md","# "+slugTitle(pn)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\nnpm run dev\n\`\`\`\n\n## Build\n\`\`\`bash\nnpm run build\n\`\`\`\n\n## Open in IDE\nOpen the project folder in VS Code or WebStorm.\n"); zip.file(folder+".gitignore","node_modules/\ndist/\n.env\n.DS_Store\n*.local\n"); } /* --- Vue (Vite + Composition API + TypeScript) --- */ function buildVue(zip,folder,app,code,panelTxt){ var pn=pkgName(app); var C=cc(pn); var extracted=extractCode(panelTxt); zip.file(folder+"package.json",'{\n "name": "'+pn+'",\n "version": "0.0.0",\n "type": "module",\n "scripts": {\n "dev": "vite",\n "build": "vue-tsc -b && vite build",\n "preview": "vite preview"\n },\n "dependencies": {\n "vue": "^3.5.13",\n "vue-router": "^4.4.5",\n "pinia": "^2.3.0",\n "axios": "^1.7.9"\n },\n "devDependencies": {\n "@vitejs/plugin-vue": "^5.2.1",\n "typescript": "~5.7.3",\n "vite": "^6.0.5",\n "vue-tsc": "^2.2.0"\n }\n}\n'); zip.file(folder+"vite.config.ts","import { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport { resolve } from 'path'\n\nexport default defineConfig({\n plugins: [vue()],\n resolve: { alias: { '@': resolve(__dirname,'src') } }\n})\n"); zip.file(folder+"tsconfig.json",'{"files":[],"references":[{"path":"./tsconfig.app.json"},{"path":"./tsconfig.node.json"}]}\n'); zip.file(folder+"tsconfig.app.json",'{\n "compilerOptions":{\n "target":"ES2020","useDefineForClassFields":true,"module":"ESNext","lib":["ES2020","DOM","DOM.Iterable"],\n "skipLibCheck":true,"moduleResolution":"bundler","allowImportingTsExtensions":true,\n "isolatedModules":true,"moduleDetection":"force","noEmit":true,"jsxImportSource":"vue",\n "strict":true,"paths":{"@/*":["./src/*"]}\n },\n "include":["src/**/*.ts","src/**/*.d.ts","src/**/*.tsx","src/**/*.vue"]\n}\n'); zip.file(folder+"env.d.ts","/// \n"); zip.file(folder+"index.html","\n\n\n \n \n "+slugTitle(pn)+"\n\n\n
\n \n\n\n"); var hasMain=Object.keys(extracted).some(function(k){return k==="src/main.ts"||k==="main.ts";}); if(!hasMain) zip.file(folder+"src/main.ts","import { createApp } from 'vue'\nimport { createPinia } from 'pinia'\nimport App from './App.vue'\nimport './assets/main.css'\n\nconst app = createApp(App)\napp.use(createPinia())\napp.mount('#app')\n"); var hasApp=Object.keys(extracted).some(function(k){return k.indexOf("App.vue")>=0;}); if(!hasApp) zip.file(folder+"src/App.vue","\n\n\n\n\n"); zip.file(folder+"src/assets/main.css","*{margin:0;padding:0;box-sizing:border-box}body{font-family:system-ui,sans-serif;background:#fff;color:#213547}\n"); zip.file(folder+"src/components/.gitkeep",""); zip.file(folder+"src/views/.gitkeep",""); zip.file(folder+"src/stores/.gitkeep",""); Object.keys(extracted).forEach(function(p){ var fp=p.startsWith("src/")?p:"src/"+p; zip.file(folder+fp,extracted[p]); }); zip.file(folder+"README.md","# "+slugTitle(pn)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\nnpm run dev\n\`\`\`\n\n## Build\n\`\`\`bash\nnpm run build\n\`\`\`\n\nOpen in VS Code or WebStorm.\n"); zip.file(folder+".gitignore","node_modules/\ndist/\n.env\n.DS_Store\n*.local\n"); } /* --- Angular (v19 standalone) --- */ function buildAngular(zip,folder,app,code,panelTxt){ var pn=pkgName(app); var C=cc(pn); var sel=pn.replace(/_/g,"-"); var extracted=extractCode(panelTxt); zip.file(folder+"package.json",'{\n "name": "'+pn+'",\n "version": "0.0.0",\n "scripts": {\n "ng": "ng",\n "start": "ng serve",\n "build": "ng build",\n "test": "ng test"\n },\n "dependencies": {\n "@angular/animations": "^19.0.0",\n "@angular/common": "^19.0.0",\n "@angular/compiler": "^19.0.0",\n "@angular/core": "^19.0.0",\n "@angular/forms": "^19.0.0",\n "@angular/platform-browser": "^19.0.0",\n "@angular/platform-browser-dynamic": "^19.0.0",\n "@angular/router": "^19.0.0",\n "rxjs": "~7.8.0",\n "tslib": "^2.3.0",\n "zone.js": "~0.15.0"\n },\n "devDependencies": {\n "@angular-devkit/build-angular": "^19.0.0",\n "@angular/cli": "^19.0.0",\n "@angular/compiler-cli": "^19.0.0",\n "typescript": "~5.6.0"\n }\n}\n'); zip.file(folder+"angular.json",'{\n "$schema": "./node_modules/@angular/cli/lib/config/schema.json",\n "version": 1,\n "newProjectRoot": "projects",\n "projects": {\n "'+pn+'": {\n "projectType": "application",\n "root": "",\n "sourceRoot": "src",\n "prefix": "app",\n "architect": {\n "build": {\n "builder": "@angular-devkit/build-angular:application",\n "options": {\n "outputPath": "dist/'+pn+'",\n "index": "src/index.html",\n "browser": "src/main.ts",\n "tsConfig": "tsconfig.app.json",\n "styles": ["src/styles.css"],\n "scripts": []\n }\n },\n "serve": {"builder":"@angular-devkit/build-angular:dev-server","configurations":{"production":{"buildTarget":"'+pn+':build:production"},"development":{"buildTarget":"'+pn+':build:development"}},"defaultConfiguration":"development"}\n }\n }\n }\n}\n'); zip.file(folder+"tsconfig.json",'{\n "compileOnSave": false,\n "compilerOptions": {"baseUrl":"./","outDir":"./dist/out-tsc","forceConsistentCasingInFileNames":true,"strict":true,"noImplicitOverride":true,"noPropertyAccessFromIndexSignature":true,"noImplicitReturns":true,"noFallthroughCasesInSwitch":true,"paths":{"@/*":["src/*"]},"skipLibCheck":true,"esModuleInterop":true,"sourceMap":true,"declaration":false,"experimentalDecorators":true,"moduleResolution":"bundler","importHelpers":true,"target":"ES2022","module":"ES2022","useDefineForClassFields":false,"lib":["ES2022","dom"]},\n "references":[{"path":"./tsconfig.app.json"}]\n}\n'); zip.file(folder+"tsconfig.app.json",'{\n "extends":"./tsconfig.json",\n "compilerOptions":{"outDir":"./dist/out-tsc","types":[]},\n "files":["src/main.ts"],\n "include":["src/**/*.d.ts"]\n}\n'); zip.file(folder+"src/index.html","\n\n\n \n "+slugTitle(pn)+"\n \n \n \n\n\n \n\n\n"); zip.file(folder+"src/main.ts","import { bootstrapApplication } from '@angular/platform-browser';\nimport { appConfig } from './app/app.config';\nimport { AppComponent } from './app/app.component';\n\nbootstrapApplication(AppComponent, appConfig)\n .catch(err => console.error(err));\n"); zip.file(folder+"src/styles.css","* { margin: 0; padding: 0; box-sizing: border-box; }\nbody { font-family: system-ui, -apple-system, sans-serif; background: #f9fafb; color: #111827; }\n"); var hasComp=Object.keys(extracted).some(function(k){return k.indexOf("app.component")>=0;}); if(!hasComp){ zip.file(folder+"src/app/app.component.ts","import { Component } from '@angular/core';\nimport { RouterOutlet } from '@angular/router';\n\n@Component({\n selector: 'app-root',\n standalone: true,\n imports: [RouterOutlet],\n templateUrl: './app.component.html',\n styleUrl: './app.component.css'\n})\nexport class AppComponent {\n title = '"+pn+"';\n}\n"); zip.file(folder+"src/app/app.component.html","
\n
\n

"+slugTitle(pn)+"

\n

Built with PantheraHive BOS

\n
\n \n
\n"); zip.file(folder+"src/app/app.component.css",".app-header{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:60vh;gap:16px}h1{font-size:2.5rem;font-weight:700;color:#6366f1}\n"); } zip.file(folder+"src/app/app.config.ts","import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';\nimport { provideRouter } from '@angular/router';\nimport { routes } from './app.routes';\n\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideZoneChangeDetection({ eventCoalescing: true }),\n provideRouter(routes)\n ]\n};\n"); zip.file(folder+"src/app/app.routes.ts","import { Routes } from '@angular/router';\n\nexport const routes: Routes = [];\n"); Object.keys(extracted).forEach(function(p){ var fp=p.startsWith("src/")?p:"src/"+p; zip.file(folder+fp,extracted[p]); }); zip.file(folder+"README.md","# "+slugTitle(pn)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\nng serve\n# or: npm start\n\`\`\`\n\n## Build\n\`\`\`bash\nng build\n\`\`\`\n\nOpen in VS Code with Angular Language Service extension.\n"); zip.file(folder+".gitignore","node_modules/\ndist/\n.env\n.DS_Store\n*.local\n.angular/\n"); } /* --- Python --- */ function buildPython(zip,folder,app,code){ var title=slugTitle(app); var pn=pkgName(app); var src=code.replace(/^\`\`\`[\w]*\n?/m,"").replace(/\n?\`\`\`$/m,"").trim(); var reqMap={"numpy":"numpy","pandas":"pandas","sklearn":"scikit-learn","tensorflow":"tensorflow","torch":"torch","flask":"flask","fastapi":"fastapi","uvicorn":"uvicorn","requests":"requests","sqlalchemy":"sqlalchemy","pydantic":"pydantic","dotenv":"python-dotenv","PIL":"Pillow","cv2":"opencv-python","matplotlib":"matplotlib","seaborn":"seaborn","scipy":"scipy"}; var reqs=[]; Object.keys(reqMap).forEach(function(k){if(src.indexOf("import "+k)>=0||src.indexOf("from "+k)>=0)reqs.push(reqMap[k]);}); var reqsTxt=reqs.length?reqs.join("\n"):"# add dependencies here\n"; zip.file(folder+"main.py",src||"# "+title+"\n# Generated by PantheraHive BOS\n\nprint(title+\" loaded\")\n"); zip.file(folder+"requirements.txt",reqsTxt); zip.file(folder+".env.example","# Environment variables\n"); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\npython3 -m venv .venv\nsource .venv/bin/activate\npip install -r requirements.txt\n\`\`\`\n\n## Run\n\`\`\`bash\npython main.py\n\`\`\`\n"); zip.file(folder+".gitignore",".venv/\n__pycache__/\n*.pyc\n.env\n.DS_Store\n"); } /* --- Node.js --- */ function buildNode(zip,folder,app,code){ var title=slugTitle(app); var pn=pkgName(app); var src=code.replace(/^\`\`\`[\w]*\n?/m,"").replace(/\n?\`\`\`$/m,"").trim(); var depMap={"mongoose":"^8.0.0","dotenv":"^16.4.5","axios":"^1.7.9","cors":"^2.8.5","bcryptjs":"^2.4.3","jsonwebtoken":"^9.0.2","socket.io":"^4.7.4","uuid":"^9.0.1","zod":"^3.22.4","express":"^4.18.2"}; var deps={}; Object.keys(depMap).forEach(function(k){if(src.indexOf(k)>=0)deps[k]=depMap[k];}); if(!deps["express"])deps["express"]="^4.18.2"; var pkgJson=JSON.stringify({"name":pn,"version":"1.0.0","main":"src/index.js","scripts":{"start":"node src/index.js","dev":"nodemon src/index.js"},"dependencies":deps,"devDependencies":{"nodemon":"^3.0.3"}},null,2)+"\n"; zip.file(folder+"package.json",pkgJson); var fallback="const express=require(\"express\");\nconst app=express();\napp.use(express.json());\n\napp.get(\"/\",(req,res)=>{\n res.json({message:\""+title+" API\"});\n});\n\nconst PORT=process.env.PORT||3000;\napp.listen(PORT,()=>console.log(\"Server on port \"+PORT));\n"; zip.file(folder+"src/index.js",src||fallback); zip.file(folder+".env.example","PORT=3000\n"); zip.file(folder+".gitignore","node_modules/\n.env\n.DS_Store\n"); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\n\`\`\`\n\n## Run\n\`\`\`bash\nnpm run dev\n\`\`\`\n"); } /* --- Vanilla HTML --- */ function buildVanillaHtml(zip,folder,app,code){ var title=slugTitle(app); var isFullDoc=code.trim().toLowerCase().indexOf("=0||code.trim().toLowerCase().indexOf("=0; var indexHtml=isFullDoc?code:"\n\n\n\n\n"+title+"\n\n\n\n"+code+"\n\n\n\n"; zip.file(folder+"index.html",indexHtml); zip.file(folder+"style.css","/* "+title+" — styles */\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:system-ui,-apple-system,sans-serif;background:#fff;color:#1a1a2e}\n"); zip.file(folder+"script.js","/* "+title+" — scripts */\n"); zip.file(folder+"assets/.gitkeep",""); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\n## Open\nDouble-click \`index.html\` in your browser.\n\nOr serve locally:\n\`\`\`bash\nnpx serve .\n# or\npython3 -m http.server 3000\n\`\`\`\n"); zip.file(folder+".gitignore",".DS_Store\nnode_modules/\n.env\n"); } /* ===== MAIN ===== */ var sc=document.createElement("script"); sc.src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"; sc.onerror=function(){ if(lbl)lbl.textContent="Download ZIP"; alert("JSZip load failed — check connection."); }; sc.onload=function(){ var zip=new JSZip(); var base=(_phFname||"output").replace(/\.[^.]+$/,""); var app=base.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"my_app"; var folder=app+"/"; var vc=document.getElementById("panel-content"); var panelTxt=vc?(vc.innerText||vc.textContent||""):""; var lang=detectLang(_phCode,panelTxt); if(_phIsHtml){ buildVanillaHtml(zip,folder,app,_phCode); } else if(lang==="flutter"){ buildFlutter(zip,folder,app,_phCode,panelTxt); } else if(lang==="react-native"){ buildReactNative(zip,folder,app,_phCode,panelTxt); } else if(lang==="swift"){ buildSwift(zip,folder,app,_phCode,panelTxt); } else if(lang==="kotlin"){ buildKotlin(zip,folder,app,_phCode,panelTxt); } else if(lang==="react"){ buildReact(zip,folder,app,_phCode,panelTxt); } else if(lang==="vue"){ buildVue(zip,folder,app,_phCode,panelTxt); } else if(lang==="angular"){ buildAngular(zip,folder,app,_phCode,panelTxt); } else if(lang==="python"){ buildPython(zip,folder,app,_phCode); } else if(lang==="node"){ buildNode(zip,folder,app,_phCode); } else { /* Document/content workflow */ var title=app.replace(/_/g," "); var md=_phAll||_phCode||panelTxt||"No content"; zip.file(folder+app+".md",md); var h=""+title+""; h+="

"+title+"

"; var hc=md.replace(/&/g,"&").replace(//g,">"); hc=hc.replace(/^### (.+)$/gm,"

$1

"); hc=hc.replace(/^## (.+)$/gm,"

$1

"); hc=hc.replace(/^# (.+)$/gm,"

$1

"); hc=hc.replace(/\*\*(.+?)\*\*/g,"$1"); hc=hc.replace(/\n{2,}/g,"

"); h+="

"+hc+"

Generated by PantheraHive BOS
"; zip.file(folder+app+".html",h); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\nFiles:\n- "+app+".md (Markdown)\n- "+app+".html (styled HTML)\n"); } zip.generateAsync({type:"blob"}).then(function(blob){ var a=document.createElement("a"); a.href=URL.createObjectURL(blob); a.download=app+".zip"; a.click(); URL.revokeObjectURL(a.href); if(lbl)lbl.textContent="Download ZIP"; }); }; document.head.appendChild(sc); } function phShare(){navigator.clipboard.writeText(window.location.href).then(function(){var el=document.getElementById("ph-share-lbl");if(el){el.textContent="Link copied!";setTimeout(function(){el.textContent="Copy share link";},2500);}});}function phEmbed(){var runId=window.location.pathname.split("/").pop().replace(".html","");var embedUrl="https://pantherahive.com/embed/"+runId;var code='';navigator.clipboard.writeText(code).then(function(){var el=document.getElementById("ph-embed-lbl");if(el){el.textContent="Embed code copied!";setTimeout(function(){el.textContent="Get Embed Code";},2500);}});}