DEV Community

Cover image for Never lose valuable error context in JavaScript
Amnish Singh Arora
Amnish Singh Arora

Posted on • Edited on

Never lose valuable error context in JavaScript

If you are a JavaScript developer, you might have ran into error messages like:

  • Failed to extract text from the file
  • Failed to save entity
  • And so on...

But what exactly led to failing of an entire high-level operation?

We don't know the answer because we didn't do a good enough job to preserve the error context, when throwing a specific error that is a symptom of a more low level cause.

Frustrated developer breaking PC

For years, JavaScript developers have struggled to preserve appropriate error context when throwing exceptions, as there was no in-built mechanism provided by the language to attach error cause, unlike other languages like Java, Python and C#.

This problem was solved by Node, when they finally added a cause property to their Error constructor in v16.9.0, which means you could now throw exceptions like so:

try {
    await fetch("some-resource");
}
catch(error) {
    throw new Error("Specific error message", {
        cause: error
    });
}
Enter fullscreen mode Exit fullscreen mode

This means you now get to preserve the entire context of the original error that led to throwing of a high level exception (including its message and stack trace).

Table of Contents

 1. The problem
 2. The solution?
 3. Installation
 4. Configuration
       4.1. VSCode Extension
 5. Conclusion

The problem

This feature has been available in Node for a while now (added in 2022), and although it solves the big problem of not having a standard way to preserve error context, it introduces a new problem as its completely optional to attach the error cause to new exceptions.

The solution?

What we need is a static analysis tool to enforce this as a coding convention — ensuring developers always attach available causes when throwing new errors.

While ESLint is the go-to tool for code quality in JavaScript, it doesn’t provide any built-in rule for this.

So I decided to write one myself!

Introducing eslint-plugin-error-cause — an ESLint plugin that flags any throw new Error(...) calls that omit the cause when inside a catch block.

Let's talk about how we can set this up in our projects.

Installation

The very first thing you need to do is install the plugin and eslint as dev dependencies in your project. This example uses pnpm, but you could use a package manager of your choice.

pnpm add -D eslint eslint-plugin-error-cause
Enter fullscreen mode Exit fullscreen mode

Configuration

1. Once installed, create an eslint.config.js file at the root of your project.

2. There are two ways to add this plugin to your eslint configuration.

  • Use the in-built recommended config, that enables no-swallowed-error-cause rule with a severity level of warn.
import errorCause from "eslint-plugin-error-cause";
import { defineConfig } from "eslint/config";

export default defineConfig([errorCause.configs.recommended]);
Enter fullscreen mode Exit fullscreen mode
  • Enable the rule manually with a severity level of your choice.
import errorCause from "eslint-plugin-error-cause";
import { defineConfig } from "eslint/config";

export default defineConfig([
    {
        plugins: {
            "error-cause": errorCause,
        },
        rules: {
            "error-cause/no-swallowed-error-cause": "warn",
        },
    },
]);
Enter fullscreen mode Exit fullscreen mode

3. Setup lint scripts in your package.json.

"scripts": {
    ...
    "lint": "eslint .",
    "lint:fix":  "pnpm lint --fix",
    ...
},
Enter fullscreen mode Exit fullscreen mode

4. Use the lint script to report all the lint errors in your code. 🎊

> pnpm lint

3:10  error    'rootError' is defined but never used                                 no-unused-vars
4:5   warning  Include the original caught error as the `cause` of the custom error  error-cause/no-swallowed-error-cause
Enter fullscreen mode Exit fullscreen mode

5. Use --fix to fix any instances on no-swallowed-error-cause.

> pnpm lint:fix
Enter fullscreen mode Exit fullscreen mode

VSCode Extension

Almost everyone uses ESLint's VSCode extension to detect and fix lint errors in-place when coding.

If you don't have it setup, follow these steps:

1. Install the ESLint extension.

Eslint VSCode Extension

2. Add this setting to your workspace/user settings.json. You could add/omit the JavaScript flavours based on your project needs.

"eslint.validate": [
  "javascript",
  "javascriptreact",
  "typescript",
  "typescriptreact"
  ],
Enter fullscreen mode Exit fullscreen mode

3. Now you can detect and fix swallowed error causes using VSCode's UI.

Plugin in Action

Conclusion

So that's all about how you could setup my new plugin in your projects, and never again worry about missing important error context when throwing custom exceptions!

This plugin is still very new and might not cover some edge-cases. I welcome any interested readers to visit the GitHub repo, open issues, send in pull requests, or even give it a star and share with your connections if this helped you in any way 😁

Github: https://github.com/Amnish04/eslint-plugin-error-cause

NPM: https://www.npmjs.com/package/eslint-plugin-error-cause

Top comments (6)

Collapse
 
nevodavid profile image
Nevo David

yeah this is super clutch tbh, i’ve lost so much time digging for those swallowed errors - you think more teams would actually adopt this kinda stuff if it flagged in ci?

Collapse
 
amnish04 profile image
Amnish Singh Arora

I'd say every team should properly enforce this standard. Our team at DeepStructure found it useful to the point I decided to write this plugin!

Collapse
 
dotallio profile image
Dotallio

Love this, autofix support and VSCode integration are super helpful touches.
Any plans for handling custom error types or async callbacks in the future?

Collapse
 
amnish04 profile image
Amnish Singh Arora • Edited

Glad you liked it! Happy to handle any remaining edge cases/improvements as follow ups.

Please file issues on the Github repo with full details and examples, so we can keep track of it. You could even send in a PR if you want to :)

github.com/Amnish04/eslint-plugin-...

Collapse
 
nathan_tarbert profile image
Nathan Tarbert

pretty cool, i've always wanted a better way to catch where stuff blows up in my code

Collapse
 
amnish04 profile image
Amnish Singh Arora • Edited

Glad you found it useful! I would really appreciate a star to the repo as it helps promote the project :D