Pony Cause 1.0: Error Causes
Tags: javascript, node, typescript, showdev
Published: 2021-09-20 15:35:53

[Pony Cause](https://github.com/voxpelli/pony-cause) is my new [ponyfill](https://ponyfill.com/) and helpers for the new [Error Cause](https://github.com/tc39/proposal-error-cause) tc39 [proposal](https://github.com/tc39/proposals).

The ponyfill as well as the proposal aims to replace VError / NError with a standard mechanism for wrapping errors and improving error contexts.

## How does it wrap errors?

The Error Cause proposals add a second argument to the `Error` constructor.

The new argument is a plain object with so far `cause` as its only defined key.

`cause` is intended to be the value of a caught error.

That way `cause` enables an `Error` of a higher level to reference one of a lower level error, adding context without sacrificing detail.

An example:

```javascript
try {
  // ...
  throw new Error('ABC123 exception encountered in database "Foo"');
} catch (err) {
  throw new Error('Failed to save blog post', { cause: err })
}
```

The `Failed to save blog post` message provides a higher level context, it tells us _what_ has happened, it tells us the _impact_.

The inner `ABC123 exception encountered in database "Foo"` message tells us _why_ this happened, it tells us the _cause_.

## So why wrap errors?

In classic JavaScript it has been an either or – either getting to know the _impact_ or the _cause_, but never both `Error`:s (unless one has logged them separately or have used VError / NError).

The _impact_ and _cause_ provides the most value when paired with the other, and that's what [Error Cause](https://github.com/tc39/proposal-error-cause) enables and what [Pony Cause is](https://github.com/voxpelli/pony-cause) is a [ponyfill](https://ponyfill.com/) for and provides helpers for.

## What does `pony-cause` add?

[Pony Cause is](https://github.com/voxpelli/pony-cause) consist of two parts:

1. A [ponyfill](https://ponyfill.com/) in the shape of a `ErrorWithCause` class which mimics the new cause-supporting `Error` class.
2. A couple of `VError`-inspired helpers for working with error causes, ensuring that the added context becomes actually useful. These helpers also supports `VError` style causes on top of the new error causes, enabling a smooth transition from one to the other.

## Which helpers does it add?

* [`findCauseByReference(err, Error)`](https://github.com/voxpelli/pony-cause#findcausebyreference-finding-a-specific-type-of-error-in-the-cause-chain)
* [`getErrorCause(err)`](https://github.com/voxpelli/pony-cause#geterrorcause-getting-the-cause-of-an-error)
* [`stackWithCauses(err)`](https://github.com/voxpelli/pony-cause#stackwithcauses-getting-full-stack-trace-for-error--all-causes)

## Anything else I should know?

Pony Cause is written in JS, typed with JSDoc, validated with TypeScript and have .d.ts / .d.ts.map generated by TypeScript. In other words: `100% typed` in true [Types in JS](https://github.com/voxpelli/types-in-js) spirit.

It's a CommonJS module rather than ESM, to maximise compatibility here and now, as that's the point of a ponyfill.

It's licensed under the [`0BSD`](https://choosealicense.com/licenses/0bsd/) license, a BSD/MIT-style license with the requirement for attribution removed.


## Will there be native support?

Yes, it's recently been implemented in [all three major browsers](https://caniuse.com/mdn-javascript_builtins_error_cause) and V8 [shipped native support](https://v8.dev/blog/v8-release-93#error-cause) a bit over a month ago with eg. [Node.js v16.9.0](https://nodejs.org/en/blog/release/v16.9.0/#error-cause) and [Deno v1.13](https://deno.com/blog/v1.13#error-cause) both having already shipped with that version of V8.

Though you still need a ponyfill or polyfill if you want to support older browsers or older Node.js versions.

[Pony Cause](https://github.com/voxpelli/pony-cause) also provides helpers which are useful no matter if you're using it with old environments or not it is a module that your toolbox needs 😉