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

error-human-format

v1.1.1

Published

Intelligent error explanation engine — converts raw JS/Node.js errors (including Prisma) into human-readable explanations with actionable debugging suggestions

Downloads

789

Readme

error-human-format

Intelligent error explanation engine for JavaScript and Node.js.
Converts raw errors into human-readable explanations with actionable debugging suggestions.

npm version License: MIT TypeScript


Why?

Raw JavaScript errors tell you what broke. error-human-format tells you why it likely broke and how to fix it — instantly, without leaving your terminal or codebase.

❌  Accessed property "id" on undefined

👉  Explanation
    You tried to read the property "id" from a value that is undefined.
    This usually means a variable was never assigned, an async operation
    hadn't finished yet, or an API returned undefined unexpectedly.

🔍  Possible Causes
    • A variable was declared but never initialised (it stayed undefined)
    • An asynchronous operation completed but the result wasn't awaited
    • An API call or function returned an unexpected null/undefined

💡  Suggestions
    1. Add a null-check before accessing: `if (obj != null) { obj.id … }`
    2. Use optional chaining: `obj?.id`
    3. Use nullish coalescing as a fallback: `(obj ?? defaultValue).id`
    4. Verify the variable is properly initialised before this line

📍  Location
    /app/src/handler.ts:42:8 (handleRequest)

📊  Confidence: 97%

Installation

npm install error-human-format
# or
pnpm add error-human-format
# or
yarn add error-human-format

For the CLI tool, install globally:

npm install -g error-human-format

Quick Start

Programmatic API

import { humanize } from 'error-human-format';

try {
  // your code
} catch (err) {
  const result = await humanize(err);

  console.log(result.title);          // "Accessed property "id" on undefined"
  console.log(result.explanation);    // Plain-English explanation
  console.log(result.possibleCauses); // string[]
  console.log(result.suggestions);    // string[]
  console.log(result.confidence);     // 0–1 score
  console.log(result.location);       // { fileName, lineNumber, … }
}

CLI

# Analyse an error message
error-human-format "Cannot read properties of undefined (reading 'id')"

# Pipe a stack trace
cat error.log | error-human-format

# Output raw JSON
error-human-format "myVar is not defined" --json

# Include the stack trace in output
error-human-format "ECONNREFUSED 127.0.0.1:5432" --stack

# Disable colours (e.g. for CI)
error-human-format "Unexpected end of JSON input" --no-color

API Reference

humanize(input, options?)

Converts any error into a structured HumanizedError report.

import { humanize } from 'error-human-format';

const result = await humanize(input, options);

Input — accepts any of:

| Type | Example | |------|---------| | Error (or subclass) | new TypeError("…") | | string | "Cannot read properties of undefined…" | | Stack trace string | Full multi-line stack trace | | { message, stack? } | Plain object |

Options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | includeStack | boolean | false | Attach raw stack trace to the result | | verbose | boolean | false | Log normalisation/match decisions | | debugMode | boolean | false | Print internal pattern matching details | | color | boolean | false | Apply ANSI colour codes to string fields | | aiFallback | AiFallbackHandler | — | Called when no pattern matches |

Return type — HumanizedError:

interface HumanizedError {
  title:          string;       // Short, descriptive title
  explanation:    string;       // Plain-English explanation
  possibleCauses: string[];     // List of likely root causes
  suggestions:    string[];     // Actionable fix steps
  confidence:     number;       // 0–1 match confidence
  location?:      StackFrame;   // Parsed stack location
  errorType?:     string;       // e.g. "TypeError"
  stack?:         string;       // Raw stack (when includeStack: true)
}

registerPattern(pattern)

Register a custom (or override a built-in) pattern.

import { registerPattern } from 'error-human-format';

registerPattern({
  id: 'my_app.db_connection',
  name: 'Database Connection Error',
  matcher: /SQLITE_CANTOPEN: unable to open database file (?<file>.+)/,
  extractor: (match) => ({ file: match.groups?.file ?? '<unknown>' }),
  titleBuilder:       ({ file }) => `Cannot open SQLite database: ${file}`,
  explanationBuilder: ({ file }) =>
    `SQLite could not open the database file at "${file}". ` +
    `The file may not exist, or the process lacks read/write permissions.`,
  causesBuilder: () => [
    'The database file path is wrong',
    'The directory does not exist',
    'Insufficient file system permissions',
  ],
  suggestionsBuilder: ({ file }) => [
    `Verify the path exists: \`ls -la ${file}\``,
    'Check process permissions: `ls -l $(dirname <file>)`',
    'Create the directory if missing: `mkdir -p $(dirname <file>)`',
  ],
  confidence: 0.96,
  tags: ['database', 'sqlite'],
});

registry

Direct access to the global pattern registry (for advanced use):

import { registry } from 'error-human-format';

console.log(registry.size);            // number of registered patterns
const pattern = registry.get('type_error.cannot_read_props');
const all     = registry.getSorted();  // sorted by confidence desc

Stack Trace Utilities

import {
  parseStackTrace,
  getMostRelevantFrame,
  formatFrame,
} from 'error-human-format';

const frames  = parseStackTrace(err.stack ?? '');
const topFrame = getMostRelevantFrame(frames);
const label    = formatFrame(topFrame!); // "/app/src/handler.ts:42:8 (handleRequest)"

Express Middleware

import express from 'express';
import { errorHumanizerMiddleware } from 'error-human-format/middleware';

const app = express();

app.get('/example', (req, res) => {
  throw new TypeError("Cannot read properties of undefined (reading 'userId')");
});

// Must be registered AFTER your routes, with 4 parameters
app.use(errorHumanizerMiddleware({
  exposeToClient: true,   // send humanized JSON to client
  includeStack: false,    // don't leak internals
}));

app.listen(3000);

Response shape:

{
  "error": {
    "title": "Accessed property \"userId\" on undefined",
    "explanation": "You tried to read…",
    "suggestions": ["Add a null-check…", "Use optional chaining…"],
    "confidence": 0.97
  }
}

Custom logger and response transformer:

app.use(errorHumanizerMiddleware({
  exposeToClient: true,
  logger: (result, req) => {
    myMonitoringService.track({ title: result.title, path: req.path });
  },
  responseTransformer: (result, req) => ({
    success: false,
    requestId: req.headers['x-request-id'],
    error: result,
  }),
}));

AI Fallback

When no built-in pattern matches, you can plug in any AI provider:

import { humanize } from 'error-human-format';
import Anthropic from '@anthropic-ai/sdk';

const anthropic = new Anthropic();

const result = await humanize(err, {
  aiFallback: async (message, errorType) => {
    const response = await anthropic.messages.create({
      model: 'claude-opus-4-5',
      max_tokens: 512,
      messages: [{
        role: 'user',
        content: `Explain this ${errorType ?? 'JavaScript'} error to a developer:
"${message}"
Respond with JSON: { title, explanation, possibleCauses: string[], suggestions: string[], confidence: number }`,
      }],
    });

    const text = response.content[0].type === 'text' ? response.content[0].text : '';
    return JSON.parse(text);
  },
});

The fallback is never a hard dependency — import it only when you need it.


Built-in Error Coverage

| Category | Patterns | |----------|----------| | TypeError | undefined/null property access & mutation, not-a-function, not-iterable, null-to-object | | ReferenceError | Variable not defined, Temporal Dead Zone (let/const) | | SyntaxError / JSON | Unexpected token, end of JSON input, invalid chars after JSON, strict-mode violations | | Network | ECONNREFUSED, ECONNRESET, ETIMEDOUT, ENOTFOUND, HTTP 4xx/5xx, fetch failures, invalid JSON responses | | Promises | Unhandled rejections, await outside async, Promise.all failures | | Modules | Cannot find module, require in ESM, missing named exports |


Plugin Architecture

Every pattern is an ErrorPattern object stored in src/patterns/. Adding support for a new library is a single file:

// src/patterns/prismaErrors.ts
import type { ErrorPattern } from '../types/index.js';

const prismaErrorPatterns: ErrorPattern[] = [
  {
    id: 'prisma.record_not_found',
    name: 'Prisma Record Not Found',
    matcher: /An operation failed because it depends on one or more records that were required but not found/,
    // ...
  },
];

export default prismaErrorPatterns;

Then add it to src/core/registry.ts:

import prismaErrorPatterns from '../patterns/prismaErrors.js';
// add to the builtIn array

Performance

  • Pattern matching is O(n) on the number of patterns, with early exit on first match.
  • Patterns are sorted once by confidence and cached — subsequent calls hit the cache.
  • No heavy runtime dependencies (only chalk and commander for the CLI).
  • Zero async work unless an AI fallback is configured.

Project Structure

error-human-format/
├── src/
│   ├── core/
│   │   ├── humanizer.ts      # humanize() + registerPattern()
│   │   ├── matcher.ts        # Pattern matching engine
│   │   └── registry.ts       # PatternRegistry (singleton + class)
│   ├── patterns/
│   │   ├── typeErrors.ts     # TypeError patterns
│   │   ├── referenceErrors.ts
│   │   ├── syntaxErrors.ts
│   │   ├── networkErrors.ts
│   │   ├── promiseErrors.ts
│   │   └── moduleErrors.ts
│   ├── utils/
│   │   ├── stackParser.ts    # Stack trace parsing
│   │   └── normalizer.ts     # Input normalisation
│   ├── cli/
│   │   ├── index.ts          # CLI entry point (Commander)
│   │   └── formatter.ts      # Coloured output
│   ├── middleware/
│   │   └── index.ts          # Express error middleware
│   ├── types/
│   │   └── index.ts          # All exported TypeScript types
│   └── index.ts              # Public package entry point
├── tests/
│   ├── unit/
│   │   ├── stackParser.test.ts
│   │   ├── normalizer.test.ts
│   │   ├── patterns.test.ts
│   │   └── formatter.test.ts
│   └── integration/
│       └── humanize.test.ts
├── dist/                     # Compiled output (CJS + ESM + .d.ts)
├── package.json
├── tsconfig.json
└── vitest.config.ts

Development

# Install dependencies
npm install

# Run tests
npm test

# Watch mode
npm run test:watch

# Coverage report
npm run test:coverage

# Type check
npm run typecheck

# Build
npm run build

Contributing

Contributions are welcome! The easiest way to contribute is to add a new pattern for an error you encounter:

  1. Identify the error message and its variants.
  2. Create (or add to) the relevant file in src/patterns/.
  3. Write a matching test in tests/unit/patterns.test.ts.
  4. Open a PR — that's it!

Please ensure:

  • All tests pass (npm test)
  • TypeScript compiles cleanly (npm run typecheck)
  • Patterns have a realistic confidence value (high = very specific match)

VS Code Extension (Architecture Note)

error-human-format is designed to be extension-ready. The core humanize() function has no Node.js-specific dependencies and can run in a VS Code extension host. A VS Code extension can:

  1. Subscribe to the language server's diagnostic events.
  2. Pass error messages to humanize().
  3. Show the structured output in a hover tooltip or side panel.

License

MIT © error-human-format contributors