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

conway-errors

v3.2.1

Published

A convenient primitive for creating, structing and throwing errors

Readme

conway-errors

npm version Downloads

RU Translation

JS/TS library for creating structured and readable errors

Why conway-errors?

  • 🎯 Structured Error Hierarchy: Organize errors by context and functionality
  • 📝 Readable Error Messages: Clear, contextual messages with complete information
  • 🔧 Flexible Configuration: Full control over throwing and logging
  • 🏗️ Separation of Concerns: Elegant programmatic API for domain and team separation
  • 📊 Tracker Integration: Easy integration with error monitoring tools like Sentry, PostHog
ConwayError [BackendLogicError]: PaymentForm/APIError/APIPaymentError: Payment already processed
    at createNewErrorObject (/project/index.ts:205:23)
    at Object.<anonymous> (/project/index.test.ts:26:1)
    at Module._compile (node:internal/modules/cjs/loader:1740:14)
    at Module.m._compile (/project/node_modules/ts-node/src/index.ts:1618:23)
    at node:internal/modules/cjs/loader:1905:10

Quick Start

1. Installation

npm install conway-errors

2. Basic Setup

import { createError } from "conway-errors";

// Define your error types
const createErrorContext = createError([
  { errorType: "ValidationError" },
  { errorType: "NetworkError" },
] as const);

// Create your first error context
const appErrors = createErrorContext("MyApp");

3. Create and Throw Errors

// Create an error
const loginError = appErrors.feature("LoginError");

throw loginError("ValidationError", "Invalid email format");
// Result: ValidationError: MyApp/LoginError: Invalid email format

Examples

Simple Structure

import { createError } from "conway-errors";

// Configure error types for your application
const createErrorContext = createError([
  { errorType: "ValidationError" },
  { errorType: "NetworkError" },
  { errorType: "BusinessLogicError" },
] as const);

// Create your application's root error context
const appErrors = createErrorContext("ECommerceApp");

// Create specific errors
const userRegistration = appErrors.feature("UserRegistration");
const paymentProcessing = appErrors.feature("PaymentProcessing");

// Throw contextual errors
try {
  // Some validation logic
  throw userRegistration("ValidationError", "Email already exists");
} catch (error) {
  console.log(error.message);
  // Output: "ValidationError: ECommerceApp/UserRegistration: Email already exists"
}

// Log errors without throwing
paymentProcessing("NetworkError", "Payment gateway timeout").emit();

Hierarchical Error Organization

import { createError } from "conway-errors";

// Setup error configuration
const createErrorContext = createError([
  { errorType: "FrontendLogicError" },
  { errorType: "BackendLogicError" },
] as const);

// Create root context
const errorContext = createErrorContext("MyProject");

// Create organized subcontexts
const apiErrorContext = errorContext.subcontext("APIError");
const authErrorContext = errorContext.subcontext("AuthError");

// Create specific error functions
const oauthError = authErrorContext.feature("OauthError");
const apiPaymentError = apiErrorContext.feature("APIPaymentError");

// Throw errors
throw oauthError("FrontendLogicError", "User not found");
// Result: "FrontendLogicError: MyProject/AuthError/OauthError: User not found"

throw apiPaymentError("BackendLogicError", "Payment already processed");
// Result: "BackendLogicError: MyProject/APIError/APIPaymentError: Payment already processed"

Separate Root Contexts

import { createError } from "conway-errors";

// Configure API-specific error types
const createAPIErrorContext = createError([
  { errorType: "MissingRequiredHeader" },
  { errorType: "InvalidInput" },
  { errorType: "InternalError" },
  { errorType: "RateLimitExceeded" },
] as const);

// Create service-specific error contexts
const authAPIErrors = createAPIErrorContext("AuthAPI");
const stockAPIErrors = createAPIErrorContext("StockAPI");

// Create feature-specific error handlers
const loginError = authAPIErrors.feature("LoginError");
const registerError = authAPIErrors.feature("RegisterError");
const stockSearchError = stockAPIErrors.feature("StockSearchError");

// Handle different error scenarios
try {
  // API call logic
  throw loginError("InvalidInput", "Invalid email format");
} catch (error) {
  // Handle login validation errors
}

// Log errors for monitoring
stockSearchError("RateLimitExceeded", "API quota exceeded").emit();

Domain-Driven Error Organization

import { createError } from "conway-errors";

// Separate type sets for different contexts
const createPaymentErrors = createError([
  { errorType: "ValidationError" },
  { errorType: "ProcessingError" },
  { errorType: "GatewayError" },
] as const);

const createAuthErrors = createError([
  { errorType: "AuthenticationError" },
  { errorType: "AuthorizationError" },
  { errorType: "TokenError" },
] as const);

// Payment domain errors
const paymentErrors = createPaymentErrors("Payment");
const recurringPayments = paymentErrors.subcontext("Recurring");
const refunds = paymentErrors.subcontext("Refund");

const recurringError = recurringPayments.feature("RecurringPaymentError");
const refundError = refunds.feature("RefundError");

// Auth domain errors
const authErrors = createAuthErrors("Authentication");
const oauthError = authErrors.feature("OAuthError");

// Usage examples
throw recurringError("ProcessingError", "Card declined for recurring payment");
throw oauthError("TokenError", "OAuth token has expired");

Advanced Usage

Team-Based Error Organization

Associate errors with teams for better debugging:

import { createError } from "conway-errors";

const createErrorContext = createError([
  { errorType: "FrontendLogicError" },
  { errorType: "BackendLogicError" },
] as const);

const projectErrors = createErrorContext("MyProject");

// Method 1: Using extendedParams for team attribution (recommended)
const authErrors = projectErrors.subcontext("Auth", {
  extendedParams: { team: "Platform Team", component: "Authentication" }
});

const searchErrors = projectErrors.subcontext("Search", {
  extendedParams: { team: "User Experience Team", component: "Search" }
});

// Method 2: Team-specific root contexts
const platformErrors = createErrorContext("PlatformTeam");
const uxErrors = createErrorContext("UXTeam");

Configuration Options

Error Monitoring Integration

Sentry Integration

Override .emit() to send events to Sentry:

import { createError } from "conway-errors";
import * as Sentry from "@sentry/nextjs";

const createErrorContext = createError([
  { errorType: "FrontendLogicError" },
  { errorType: "BackendLogicError" }
] as const, {
  // Custom error handling for monitoring
  handleEmit: (err) => {
    Sentry.captureException(err);
  },
});

const appErrors = createErrorContext("MyApp");
const userError = appErrors.feature("UserAction");

// Automatically logs to Sentry when using emit()
userError("FrontendLogicError", "Form validation failed").emit();

PostHog Integration

Integrate with PostHog for error tracking with user analytics:

import { createError } from "conway-errors";
import posthog from "posthog-js";

const createErrorContext = createError([
  { errorType: "ValidationError" },
  { errorType: "NetworkError" },
  { errorType: "BusinessLogicError" }
] as const, {
  extendedParams: {
    userId: null,
    sessionId: null,
    feature: null
  },
  handleEmit: (err, extendedParams) => {
    const { userId, sessionId, feature, severity = "error" } = extendedParams;
    
    // Capture exception with PostHog
    posthog.captureException(err, {
      user_id: userId,
      session_id: sessionId,
      feature: feature,
      severity: severity,
      error_context: err.name, // Conway error context path
      timestamp: Date.now()
    });
  },
});

const checkoutErrors = createErrorContext("Checkout", {
  extendedParams: { feature: "payment_flow" }
});

const paymentError = checkoutErrors.feature("PaymentProcessing");

// Error with user context for PostHog analytics
paymentError("NetworkError", "Payment gateway timeout").emit({
  extendedParams: {
    userId: "user-123",
    sessionId: "session-456",
    severity: "critical"
  }
});

Custom Error Message Formatting

import { createError } from "conway-errors";

const createErrorContext = createError([
  {
    errorType: "FrontendLogicError",
    createMessagePostfix: (originalError) => " >>> " + originalError?.message
  },
  { errorType: "BackendLogicError" },
] as const);

const context = createErrorContext("FileUpload");
const uploadError = context.feature("AvatarUpload");

try {
  await uploadAvatar();
} catch (err) {
  throw uploadError("FrontendLogicError", "Failed to upload avatar", err);
  // Result: "FrontendLogicError: FileUpload/AvatarUpload: Failed to upload avatar >>> Network timeout"
}

Extended Parameters and Metadata

Add custom metadata to errors for enhanced debugging and monitoring:

import { createError } from "conway-errors";
import * as Sentry from "@sentry/nextjs";

const createErrorContext = createError(
  ["FrontendLogicError", "BackendLogicError"],
  {
    extendedParams: {
      environment: process.env.NODE_ENV,
      version: "1.2.3"
    },
    handleEmit: (err, extendedParams) => {
      const { environment, version, severity = "error", userId, action } = extendedParams;

      Sentry.withScope(scope => {
        scope.setTags({ environment, version, action });
        scope.setUser({ id: userId });
        scope.setLevel(severity);
        Sentry.captureException(err);
      });
    },
  }
);

const paymentErrors = createErrorContext("Payment", {
  extendedParams: { service: "stripe" }
});

const cardPayment = paymentErrors.feature("CardPayment", {
  extendedParams: { region: "us-east-1" }
});

// Error with context-specific metadata
const error = cardPayment("BackendLogicError", "Payment processing failed");
error.emit({
  extendedParams: {
    userId: "user-123",
    action: "checkout",
    severity: "critical"
  }
});

TypeScript Support

Type Utilities

AnyFeatureOfSubcontext

Type-safe error handling with explicit subcontext constraints:

import { createError, AnyFeatureOfSubcontext } from "conway-errors";

const createErrorContext = createError([
  { errorType: "ValidationError" },
  { errorType: "ProcessingError" },
] as const);

const appErrors = createErrorContext("App");
const authErrors = appErrors.subcontext("Auth");

const loginError = authErrors.feature("LoginError");
const generalError = appErrors.feature("GeneralError");

// Type-safe error handler for auth-specific features
function handleAuthError(errorFeature: AnyFeatureOfSubcontext<typeof authErrors>) {
  // Only accepts features from authErrors subcontext
}

handleAuthError(loginError);    // ✅ Valid
handleAuthError(generalError);  // ❌ TypeScript error

Troubleshooting

Common Issues

Q: Error messages are not showing the full context path

A: Make sure you're using as const when defining error types:

// ✅ Correct
const createErrorContext = createError(["ValidationError"] as const);

// ❌ Incorrect
const createErrorContext = createError(["ValidationError"]);

Q: TypeScript errors when using custom error types

A: Ensure proper typing with const assertions and avoid mixing string literals with objects:

// ✅ Correct
const createErrorContext = createError([
  { errorType: "CustomError" },
  { errorType: "AnotherError" }
] as const);

Q: Extended parameters not appearing in error handlers

A: Extended parameters are inherited through the hierarchy. Child contexts override parent parameters with the same key.

Acknowledgment for Contributions