
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
error-shield
Advanced tools
Comprehensive error handling utility for Node.js & Express.js — custom error classes, async handler wrapper, Express middleware, HTTP error creators, retry logic, error chaining, and TypeScript support.
Stop writing repetitive error handling code. Error Shield gives you a battle-tested toolkit —
custom error classes, async wrappers, Express middleware, and 40+ HTTP error creators — out of the box.
| Pain Point | How Error Shield Helps |
|---|---|
| ❌ Inconsistent error responses across routes | ✅ Uniform ErrorDetails structure everywhere |
❌ Boilerplate try/catch in every async handler | ✅ asyncHandler() wraps it for you |
| ❌ Manually setting status codes & messages | ✅ 40+ pre-built Errors with correct codes |
| ❌ No context attached to errors for debugging | ✅ AppError carries structured context data |
| ❌ Missing TypeScript types for errors | ✅ Full type definitions included |
# npm
npm install error-shield
# yarn
yarn add error-shield
# pnpm
pnpm add error-shield
Get up and running in under 60 seconds:
const {
AppError,
handleError,
Errors,
expressErrorHandler,
asyncHandler,
} = require("error-shield");
// 1️⃣ Throw meaningful errors
throw Errors.notFound("User not found", { userId: 42 });
// 2️⃣ Handle & format any error
const details = handleError(new Error("Oops"), { includeStack: true });
// 3️⃣ Plug into Express with one line
app.use(expressErrorHandler({ includeTimestamp: true }));
That's it — structured errors, formatted output, and Express integration with zero boilerplate. 🎉
AppErrorCreate rich, structured errors with status codes, error codes, and arbitrary context:
const { AppError, handleError } = require("error-shield");
const error = new AppError("Something went wrong", 500, "CUSTOM_ERROR", {
userId: 123,
action: "updateProfile",
});
const errorDetails = handleError(error, {
includeStack: true,
includeTimestamp: true,
});
console.log(errorDetails);
{
"message": "Something went wrong",
"statusCode": 500,
"code": "CUSTOM_ERROR",
"context": {
"userId": 123,
"action": "updateProfile"
},
"isOperational": true,
"timestamp": "2026-02-24T10:30:00.000Z",
"stack": "Error: Something went wrong\n at ..."
}
Use pre-built error factories for common HTTP errors — no need to memorize status codes:
const { Errors } = require("error-shield");
// 🔴 400 — Bad Request
throw Errors.badRequest("Invalid input provided", { field: "email" });
// 🔒 401 — Unauthorized
throw Errors.unauthorized("Authentication required");
// 🔍 404 — Not Found
throw Errors.notFound("User not found", { userId: 123 });
// ✏️ 422 — Validation Error
throw Errors.validationError("Email is required", { field: "email" });
// 🚦 429 — Too Many Requests
throw Errors.tooManyRequests("Rate limit exceeded", { retryAfter: 60 });
// 💥 500 — Internal Server Error
throw Errors.internalServerError("Unexpected failure");
Plug in a production-ready error handler with a single line:
const express = require("express");
const { expressErrorHandler, asyncHandler, Errors } = require("error-shield");
const app = express();
// Your routes — errors are automatically caught & forwarded
app.get(
"/users/:id",
asyncHandler(async (req, res) => {
const user = await getUserById(req.params.id);
if (!user) {
throw Errors.notFound("User not found", { userId: req.params.id });
}
res.json(user);
}),
);
// ⬇️ Error handler middleware (must be last)
app.use(
expressErrorHandler({
includeStack: process.env.NODE_ENV !== "production",
includeTimestamp: true,
}),
);
app.listen(3000, () => console.log("🚀 Server running on port 3000"));
💡 Tip: Combine
asyncHandlerwithexpressErrorHandlerfor completely boilerplate-free async route error handling.
Eliminate try/catch blocks in your async route handlers:
const { asyncHandler } = require("error-shield");
// ❌ Without asyncHandler
app.get("/api/data", async (req, res, next) => {
try {
const data = await fetchData();
res.json(data);
} catch (err) {
next(err); // easy to forget!
}
});
// ✅ With asyncHandler — clean & safe
app.get(
"/api/data",
asyncHandler(async (req, res) => {
const data = await fetchData();
res.json(data);
}),
);
Attach your own logging logic — send errors to Sentry, Datadog, or any external service:
const { handleError } = require("error-shield");
const errorDetails = handleError(error, {
logger: (details) => {
console.error("[ERROR]", details.message);
// 📤 Send to your logging service
Sentry.captureException(details);
},
});
AppError classExtends the native
Errorclass with structured metadata.
class AppError extends Error {
code?: string;
statusCode?: number;
context?: Record<string, any>;
isOperational: boolean;
}
| Parameter | Type | Default | Description |
|---|---|---|---|
message | string | — | Error message |
statusCode | number | 500 | HTTP status code |
code | string | — | Machine-readable error code |
context | Record<string, any> | — | Additional debugging context |
formatError(error, options?)Formats any error into a consistent
ErrorDetailsobject.
| Parameter | Type | Description |
|---|---|---|
error | Error | AppError | The error to format |
options | ErrorHandlerOptions | Formatting options |
Returns: ErrorDetails
handleError(error, options?)Handles errors with optional logging and formatting.
| Parameter | Type | Description |
|---|---|---|
error | Error | AppError | The error to handle |
options | ErrorHandlerOptions | Handler options (includes logger, includeStack, includeTimestamp) |
Returns: ErrorDetails
asyncHandler(fn)Wraps an async Express route handler to automatically catch rejected promises.
| Parameter | Type | Description |
|---|---|---|
fn | (req, res, next) => Promise<any> | Async route handler function |
Returns: Wrapped Express middleware function
expressErrorHandler(options?)Creates an Express.js error-handling middleware.
| Parameter | Type | Description |
|---|---|---|
options | ErrorHandlerOptions | Handler options |
Returns: Express error middleware (err, req, res, next) => void
Pre-built factory methods for all standard HTTP error codes. Every method returns an AppError instance.
// Signature for all creators:
Errors.methodName(message?, context?)
// → Returns: AppError
| Method | Code | Default Message |
|---|---|---|
badRequest(message, context?) | 400 | (required) |
unauthorized(message?, context?) | 401 | Unauthorized |
paymentRequired(message?, context?) | 402 | Payment Required |
forbidden(message?, context?) | 403 | Forbidden |
notFound(message?, context?) | 404 | Not Found |
methodNotAllowed(message?, context?) | 405 | Method Not Allowed |
notAcceptable(message?, context?) | 406 | Not Acceptable |
proxyAuthRequired(message?, context?) | 407 | Proxy Authentication Required |
requestTimeout(message?, context?) | 408 | Request Timeout |
conflict(message, context?) | 409 | (required) |
gone(message?, context?) | 410 | Gone |
lengthRequired(message?, context?) | 411 | Length Required |
preconditionFailed(message?, context?) | 412 | Precondition Failed |
payloadTooLarge(message?, context?) | 413 | Payload Too Large |
uriTooLong(message?, context?) | 414 | URI Too Long |
unsupportedMediaType(message?, context?) | 415 | Unsupported Media Type |
rangeNotSatisfiable(message?, context?) | 416 | Range Not Satisfiable |
expectationFailed(message?, context?) | 417 | Expectation Failed |
imATeapot(message?, context?) | 418 | I'm a Teapot |
misdirectedRequest(message?, context?) | 421 | Misdirected Request |
unprocessableEntity(message?, context?) | 422 | Unprocessable Entity |
validationError(message, context?) | 422 | (required) |
locked(message?, context?) | 423 | Locked |
failedDependency(message?, context?) | 424 | Failed Dependency |
tooEarly(message?, context?) | 425 | Too Early |
upgradeRequired(message?, context?) | 426 | Upgrade Required |
preconditionRequired(message?, context?) | 428 | Precondition Required |
tooManyRequests(message?, context?) | 429 | Too Many Requests |
requestHeaderFieldsTooLarge(message?, context?) | 431 | Request Header Fields Too Large |
unavailableForLegalReasons(message?, context?) | 451 | Unavailable For Legal Reasons |
| Method | Code | Default Message |
|---|---|---|
internalServerError(message?, context?) | 500 | Internal Server Error |
notImplemented(message?, context?) | 501 | Not Implemented |
badGateway(message?, context?) | 502 | Bad Gateway |
serviceUnavailable(message?, context?) | 503 | Service Unavailable |
gatewayTimeout(message?, context?) | 504 | Gateway Timeout |
httpVersionNotSupported(message?, context?) | 505 | HTTP Version Not Supported |
variantAlsoNegotiates(message?, context?) | 506 | Variant Also Negotiates |
insufficientStorage(message?, context?) | 507 | Insufficient Storage |
loopDetected(message?, context?) | 508 | Loop Detected |
bandwidthLimitExceeded(message?, context?) | 509 | Bandwidth Limit Exceeded |
notExtended(message?, context?) | 510 | Not Extended |
networkAuthenticationRequired(message?, context?) | 511 | Network Authentication Required |
networkConnectTimeout(message?, context?) | 599 | Network Connect Timeout |
Error Shield ships with full TypeScript declarations — zero extra config needed.
import {
AppError,
Errors,
handleError,
asyncHandler,
expressErrorHandler,
type ErrorDetails,
type ErrorHandlerOptions,
} from "error-shield";
// Fully typed error creation
const error: AppError = Errors.notFound("User not found", {
userId: 42,
});
// Typed error details
const details: ErrorDetails = handleError(error, {
includeStack: true,
includeTimestamp: true,
});
Contributions, issues, and feature requests are welcome!
git checkout -b feature/amazing-featuregit commit -m "feat: add amazing feature"git push origin feature/amazing-featureThis project is licensed under the ISC License.
Made with ❤️ by Gopinath Kathirvel
⭐ If you found this useful, give it a star on GitHub! ⭐
FAQs
Comprehensive error handling utility for Node.js & Express.js — custom error classes, async handler wrapper, Express middleware, HTTP error creators, retry logic, error chaining, and TypeScript support.
The npm package error-shield receives a total of 10 weekly downloads. As such, error-shield popularity was classified as not popular.
We found that error-shield demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.