npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

forge-error

v0.0.4

Published

A comprehensive HTTP error handling library for Node.js applications with typed error classes and standardized error responses.

Readme

forge-error

A comprehensive and type-safe HTTP error handling library for Node.js and TypeScript applications. forge-error provides a structured, standardized, and consistent approach to defining, throwing, and handling HTTP errors with minimal boilerplate code. With fully typed error classes and built-in support for standardized error responses, it helps you write cleaner, more maintainable error handling logic in your application.

Table of Contents

  1. Installation

  2. Features

  3. Usage

  4. Error Classes

  5. Utilities

  6. Error Payload Structure

  7. Built-in Error Constants

Installation

npm install forge-error
# or
yarn add forge-error
# or
pnpm add forge-error

Features

  • Full suite of HTTP error classes (4xx and 5xx)
  • Standardized error payload structure
  • First-class TypeScript support
  • Custom error code and data support
  • Utility functions to handle, format, and inspect errors
  • Seamless integration with Express.js
  • Async controller wrapper for concise error handling

Usage

Creating Errors

You can create errors using one of the built-in error classes or create fully custom errors with ForgeError.

Using a Simple String

import { NotFoundError } from 'forge-error';

throw new NotFoundError('Resource not found');

Using a Detailed Object

import { BadRequestError } from 'forge-error';

throw new BadRequestError({
  message: 'Invalid input data',
  data: {
    field: 'email',
    issue: 'Invalid format'
  },
  errorCode: 'INVALID_EMAIL'
});

Creating a Custom Error

import { ForgeError } from 'forge-error';

throw new ForgeError(
  'Custom error occurred',
  418,
  'CUSTOM_ERROR_CODE',
  { additional: 'context' }
);

Express Integration

You can easily integrate forge-error with your Express.js application to return consistent error responses.

Wrapping Async Controllers

Use handleAsyncRequest to wrap controller logic and eliminate manual try-catch blocks:

import express, { Request, Response } from 'express';
import { handleAsyncRequest } from 'forge-error';

const app = express();

app.post('/login', handleAsyncRequest(async (req: Request, res: Response) => {
  // Your logic here
  res.status(200).json({ message: 'Login successful' });
}));

You can also export wrapped handlers:

// controllers/auth.controller.ts
app.post('/login', loginController);

const loginController = handleAsyncRequest(async (req, res) => {
  // Logic here
});

Global Error Handler

Use getForgeErrorPayload to build standardized error responses in your global error middleware:

const app = express();

app.use(routes)

app.use((error, req, res, next) => {
  const { statusCode, errorCode, message, data } = getForgeErrorPayload(error);

  res.status(statusCode).json({
    success: false,
    statusCode,
    errorCode,
    message,
    ...(data ? { data } : {})
  });
});

app.use((req, res) => {
  res.status(404).json({
    success: false,
    statusCode: 404,
    errorCode: 'NOT_FOUND',
    message: 'Resource not found'
  });
})
import { ErrorRequestHandler } from 'express';
import { getForgeErrorPayload } from 'forge-error';

const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
  const { statusCode, errorCode, message, data } = getForgeErrorPayload(err);

  res.status(statusCode).json({
    success: false,
    statusCode,
    errorCode,
    message,
    ...(data ? { data } : {})
  });
};

export { errorHandler };

Error Classes

The library provides predefined error classes corresponding to standard HTTP status codes.

Client Errors (4xx)

import {
  BadRequestError,           // 400
  UnauthorizedError,         // 401
  ForbiddenError,            // 403
  NotFoundError,             // 404
  MethodNotAllowedError,     // 405
  NotAcceptableError,        // 406
  ConflictError,             // 409
  // ... and more
} from 'forge-error';

Server Errors (5xx)

import {
  InternalServerError,       // 500
  NotImplementedError,       // 501
  BadGatewayError,           // 502
  ServiceUnavailableError,   // 503
  GatewayTimeoutError,       // 504
  // ... and more
} from 'forge-error';

Utilities

The package provides several utility functions to handle error payloads. These are divided into two categories:

Type-Specific Utilities (Return undefined for non-matching errors)

import { getErrorPayload, getClientErrorPayload, getServerErrorPayload } from 'forge-error';

// 1. Get payload for any forge error
const error1 = new NotFoundError('Resource not found');
const payload1 = getErrorPayload(error1);
// Returns: { message: 'Resource not found', statusCode: 404, errorCode: 'NOT_FOUND' }

const error2 = new Error('Regular error');
const payload2 = getErrorPayload(error2);
// Returns: undefined

// 2. Get payload only for client errors (4xx)
const clientError = new NotFoundError('Not found');
const clientPayload = getClientErrorPayload(clientError);
// Returns: { message: 'Not found', statusCode: 404, errorCode: 'NOT_FOUND' }

const serverError = new InternalServerError('Server error');
const wrongPayload = getClientErrorPayload(serverError);
// Returns: undefined

// 3. Get payload only for server errors (5xx)
const serverPayload = getServerErrorPayload(serverError);
// Returns: { message: 'Server error', statusCode: 500, errorCode: 'INTERNAL_SERVER_ERROR' }

Guaranteed Payload Utilities (Always return a payload)

import { 
  getForgeClientErrorPayload, 
  getForgeServerErrorPayload, 
  getForgeErrorPayload 
} from 'forge-error';

// 1. Always get a client error payload
const error = new Error('Unknown error');
const clientPayload = getForgeClientErrorPayload(error);
// Returns: { 
//   message: 'Unknown error', 
//   statusCode: 400,          // Default client error status
//   errorCode: 'BAD_REQUEST'  // Default client error code
// }

// 2. Always get a server error payload
const serverPayload = getForgeServerErrorPayload(error);
// Returns: {
//   message: 'Unknown error',
//   statusCode: 500,                  // Default server error status
//   errorCode: 'INTERNAL_SERVER_ERROR' // Default server error code
// }

// 3. Always get a generic error payload (uses server error defaults)
const genericPayload = getForgeErrorPayload(error);
// Returns: {
//   message: 'Unknown error',
//   statusCode: 500,
//   errorCode: 'INTERNAL_SERVER_ERROR'
// }

// Common usage in Express error handler:
app.use((error, req, res, next) => {
  // Will always return a valid error response
  const { statusCode, ...payload } = getForgeErrorPayload(error);
  res.status(statusCode).json(payload);
});
import { isClientError, isServerError, isBaseError } from 'forge-error';

const error = new NotFoundError('Resource not found');

isClientError(error);  // true
isServerError(error);  // false
isBaseError(error);    // true

Error Payload Structure

All forge errors return a standardized structure:

{
  message: string;      // Human-readable error message
  statusCode: number;   // HTTP status code
  errorCode: string;    // Error identifier
  data?: object;        // Optional additional context
}

This format is useful for consistent API responses, logging, and debugging.

Error Handling Example

try {
  // Your code here
  throw new BadRequestError('Invalid input');
} catch (error) {
  if (error instanceof BadRequestError) {
    const payload = error.buildErrorPayload();
    // Handle the error with standardized payload
    console.log(payload);
    /*
    {
      message: 'Invalid input',
      statusCode: 400,
      errorCode: 'BAD_REQUEST'
    }
    */
  }
}

Built-in Error Constants

The library includes a comprehensive set of predefined HTTP error types with their default values. You can override these defaults using a detailed object.

| Error Class | Status Code | Error Code | Default Message | |------------|-------------|------------|-----------------| | 4xx Client Errors | | BadRequestError | 400 | BAD_REQUEST | The request could not be processed due to invalid syntax or parameters | | UnauthorizedError | 401 | UNAUTHORIZED | Authentication is required to access this resource | | PaymentRequiredError | 402 | PAYMENT_REQUIRED | Payment is required to access this resource | | ForbiddenError | 403 | FORBIDDEN | You do not have permission to access this resource | | NotFoundError | 404 | NOT_FOUND | The requested resource could not be found | | MethodNotAllowedError | 405 | METHOD_NOT_ALLOWED | The requested HTTP method is not allowed for this resource | | NotAcceptableError | 406 | NOT_ACCEPTABLE | The requested content type cannot be served by this resource | | ProxyAuthenticationRequiredError | 407 | PROXY_AUTHENTICATION_REQUIRED | Proxy server authentication is required | | RequestTimeoutError | 408 | REQUEST_TIMEOUT | The server timed out waiting for the request | | ConflictError | 409 | CONFLICT | The request conflicts with the current state | | GoneError | 410 | GONE | The requested resource is no longer available | | LengthRequiredError | 411 | LENGTH_REQUIRED | Content-Length header is required | | PreconditionFailedError | 412 | PRECONDITION_FAILED | One or more conditions failed | | PayloadTooLargeError | 413 | PAYLOAD_TOO_LARGE | Request payload exceeds the limit | | URITooLongError | 414 | URI_TOO_LONG | Request URI exceeds the maximum length | | UnsupportedMediaTypeError | 415 | UNSUPPORTED_MEDIA_TYPE | The content type is not supported | | RangeNotSatisfiableError | 416 | RANGE_NOT_SATISFIABLE | The requested range cannot be satisfied | | ExpectationFailedError | 417 | EXPECTATION_FAILED | Server cannot meet the requirements | | TeapotError | 418 | IM_A_TEAPOT | I'm a teapot | | SessionExpiredError | 419 | SESSION_EXPIRED | Your session has expired. Please refresh and try again | | RateLimitError | 420 | RATE_LIMIT_EXCEEDED | Request rate limit has been exceeded | | MisdirectedRequestError | 421 | MISDIRECTED_REQUEST | The request was sent to a server unable to produce a response | | UnprocessableEntityError | 422 | UNPROCESSABLE_ENTITY | The request was well-formed but invalid | | LockedError | 423 | RESOURCE_LOCKED | The requested resource is currently locked | | FailedDependencyError | 424 | FAILED_DEPENDENCY | The request failed due to the failure of a previous request | | TooEarlyError | 425 | TOO_EARLY | The server is not ready to process the request | | UpgradeRequiredError | 426 | UPGRADE_REQUIRED | Client must upgrade to a different protocol version | | PreconditionRequiredError | 428 | PRECONDITION_REQUIRED | This request requires preconditions to be specified | | TooManyRequestsError | 429 | TOO_MANY_REQUESTS | Rate limit exceeded | | RequestHeaderFieldsTooLargeError | 431 | REQUEST_HEADERS_TOO_LARGE | Request header fields exceed maximum size | | NoResponseError | 444 | NO_RESPONSE | Server returned no information and closed the connection | | RetryWithError | 449 | RETRY_WITH | The request should be retried after performing the appropriate action | | BlockedByWindowsParentalControlsError | 450 | BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS | Access denied by Windows parental controls | | LegallyRestrictedError | 451 | LEGALLY_RESTRICTED | Access denied for legal reasons | | RequestHeaderTooLargeError | 494 | REQUEST_HEADER_TOO_LARGE | Request header is too large | | SSLCertificateError | 495 | SSL_CERTIFICATE_ERROR | SSL/TLS certificate validation error | | SSLCertificateRequiredError | 496 | SSL_CERTIFICATE_REQUIRED | A valid SSL/TLS certificate is required | | HTTPRequestSentToHTTPSPortError | 497 | HTTP_REQUEST_SENT_TO_HTTPS_PORT | An HTTP request was sent to an HTTPS port | | InvalidTokenError | 498 | INVALID_TOKEN | The token provided is invalid or has expired | | TokenRequiredError | 499 | TOKEN_REQUIRED | A valid token is required to access this resource | | ClientClosedRequestError | 499 | CLIENT_CLOSED_REQUEST | Client closed the request before the server could respond | | 5xx Server Errors | | InternalServerError | 500 | INTERNAL_SERVER_ERROR | An unexpected error occurred | | NotImplementedError | 501 | NOT_IMPLEMENTED | Not implemented | | BadGatewayError | 502 | BAD_GATEWAY | Invalid response from upstream server | | ServiceUnavailableError | 503 | SERVICE_UNAVAILABLE | Service temporarily unavailable | | GatewayTimeoutError | 504 | GATEWAY_TIMEOUT | Gateway timeout | | HTTPVersionNotSupportedError | 505 | HTTP_VERSION_NOT_SUPPORTED | HTTP version not supported | | VariantAlsoNegotiatesError | 506 | VARIANT_ALSO_NEGOTIATES | Server configuration error in content negotiation | | InsufficientStorageError | 507 | INSUFFICIENT_STORAGE | Insufficient storage space to complete the request | | LoopDetectedError | 508 | LOOP_DETECTED | Request processing stopped due to infinite loop detection | | BandwidthLimitExceededError | 509 | BANDWIDTH_LIMIT_EXCEEDED | Server bandwidth limit has been exceeded | | NotExtendedError | 510 | NOT_EXTENDED | Server requires additional extensions to fulfill the request | | NetworkAuthenticationRequiredError | 511 | NETWORK_AUTHENTICATION_REQUIRED | Network authentication is required |

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.