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 🙏

© 2025 – Pkg Stats / Ryan Hefner

safe-error-class

v1.1.1

Published

Better errors that are extensible and don't leak sensitive data to end-users.

Readme

safe-error-class

Better errors that are extensible and don't leak sensitive data to end-users.

Quick Start

Use SafeError as an alternative to Error. You pass in an error id, an optional error message, and an optional dictionary of facets to attach to the error. See the FAQ at the bottom for helpful hints.

import { SafeError } from 'safe-error-class';

const err = new SafeError(`SOME_ERROR_ID`, `User password was incorrect`, { email: `[email protected]` });

// All typical error properties are available as usual.
err.name; // --> SafeError
err.message; // --> SOME_ERROR_ID
err.stack; // --> SafeError: SOME_ERROR_ID...

// Plus some extra properties.
err.id; // --> SOME_ERROR_ID
err.sensitive; // --> User password was incorrect
err.facets.email; // --> [email protected]

throw err;

Chaining Errors

SafeError can also chain (or wrap) other SafeError objects as well as plain JavaScript Error objects. When constructing a new SafeError just pass whatever error you caught into the sensitive parameter (instead of a string):

function parseJSON(input: string): Object {
	try {
		return JSON.parse(input);
	} catch (err: unknown) {
		const newErr = new SafeError(`PARSE_JSON`, err, { input });
		console.log(newErr.facets.$err.message); // SyntaxError: JSON.parse: unexpected character at line 1...
		throw newErr;
	}
}

Constructor Signature

new (id: string, sensitive?: string | SafeError | Error, facets?: IErrorFacets) => SafeError;

Recommended Pattern

The recommended way to use SafeError is not to throw them around like grenades, rather you should return them from your functions, and at the callsite check whether the return value was an instance of Error or not (do not check for SafeError, see below).

You should include an error ID that can be used to identify the error in logs and programatically, but this ID must not contain any sensitive information that can't be exposed in logs or to end-users.

However, it's safe to include sensitive information in the second and third parameters, as below:

function whatIsTheMeaningOfLife(answer: number): SafeError | void {
	if (answer != 42) return new SafeError(`BAD_ANSWER`, `Everybody knows the answer is 42`, { answer });
}

const something = whatIsTheMeaningOfLife(41);
if (something instanceof Error) {
	// Handle the error.
	console.error(`${err.id} - User was out by ${42 - err.facets.answer}!`);
}

// Otherwise continue the happy path!
// ...

We do not check for an instance of SafeError at the callsite, because as we know, Error grenades can be thrown around at will in JavaScript. By far the easiest thing to do is to catch these errors and return them:

function maybeExplode(): Error | void {
	try {
		throw new Error(`Explosion incoming...`); // Some third party code...
	} catch (err: unknown) {
		return err;
	}
}

But of course JavaScript isn't that clean. Anything and everything can be thrown, not just Error's. So you might be better off wrapping whatever gets caught into a new SafeError and be done with it:

function maybeExplode(): SafeError | void {
	try {
		throw `Explosion incoming...`; // Some evil third party code...
	} catch (err: unknown) {
		return new SafeError(`WHOOPS_IT_EXPLODED`, err);
	}
}

FAQ

What is safe-error-class?

The SafeError exported by this package can be used as a drop-in alternative for the built-in JavaScript Error. You pass in an error id, an optional error message, and an optional dictionary of facets to attach to the error. The error message and facets will not be exposed in logs or to end-users by mistake because they are not included in the typical Error's message property.

Can I chain errors?

Yes you can! When you catch an error you can pass it in as the second, 'sensitive', parameter when constructing a new SafeError:

function maybeExplode(): SafeError | void {
	try {
		throw new SafeError(`SOME_ERROR`, `Something bad this way comes`);
	} catch (err: unknown) {
		return new SafeError(`WHOOPS_IT_EXPLODED`, err);
	}
}

Can I wrap errors?

Yes, see: Can I chain errors?