33

In my NodeJS program, I parse some user JSON file.

So I use :

this.config = JSON.parse(fs.readFileSync(path));

The problem is that if the json file is not correctly formated, the error thrown is like:

undefined:55
            },
            ^
SyntaxError: Unexpected token }
    at Object.parse (native)
    at new MyApp (/path/to/docker/lib/node_modules/myApp/lib/my-app.js:30:28)
...

As it is not really user friendly I would like to throw an Error specifying some user friendly message (like "your config file is not well formated") but I want to keep the stacktrace in order to point to the problematic line.

In the Java world I used throw new Exception("My user friendly message", catchedException) in order to have the original exception which caused that one.

How is it possible in the JS world?

Anthony O.
  • 22,041
  • 18
  • 107
  • 163
  • Wrap it in `try{}catch(){}` and create your own message. – Ben Fortune Sep 10 '14 at 11:10
  • Yes this is how I wanted to do at first. But I wanted to keep the original stack also, which contains the original message pointing to the problematic line (in my example)... And I can't find a "good" way to do that in the JS error handling I saw until now on the web... – Anthony O. Sep 10 '14 at 11:13
  • 1
    I actually see that my question is a duplicate of: http://stackoverflow.com/questions/17886769/how-to-chain-exceptions-in-javascript-ie-add-cause-like-in-java – Anthony O. Sep 10 '14 at 11:44
  • Node.js now supports adding specific cause of the error: https://stackoverflow.com/questions/1382107/whats-a-good-way-to-extend-error-in-javascript/69365658#69365658 – t_dom93 Sep 28 '21 at 16:54

5 Answers5

39

What I finally did is:

try {
    this.config = JSON.parse(fs.readFileSync(path));
} catch(err) {
    var newErr = new Error('Problem while reading the JSON file');
    newErr.stack += '\nCaused by: '+err.stack;
    throw newErr;
}
Anthony O.
  • 22,041
  • 18
  • 107
  • 163
  • 3
    And yet the ["primary source"](https://www.joyent.com/developers/node/design/errors) regarding best practices mentions not to touch the "stack" property at all. In java there's a "cause" property. Do nodejs people expect that to be set? – dmansfield Sep 14 '15 at 15:04
  • A better answer would be something that only calculates the stack when it is read. Something like Object.defineProperty(newErr, 'stack', {get: function() { return ??? + '\nCaused by: ' + err.stack } }). But barring that, this seems pretty nice to me. – Adam A Apr 26 '16 at 06:28
  • 1
    I assume the last line should be: `throw newErr;` – fmpdmb Sep 16 '16 at 16:55
  • this is what i was looking for thanks. This is a clear example of what to do when you have a custom stack trace and you are throwing an error from a controlled situation (ie when a library provides you a with a stacktrace without an error) – Illiax May 14 '18 at 21:17
10

There is an new Error Cause proposal for ECMAScript, and it reached stage-4 at TC34!

It means it will be in the next ECMAScript version!

https://github.com/tc39/proposal-error-cause

You would provide the cause as an error option:

throw new Error(`Couldn't parse file at path ${filePath}`, { cause: err });

The ES proposal only formalize it on the language level, but browsers/NodeJS should normally agree to log the full causal chain in practice (see https://github.com/nodejs/node/issues/38725)


As of today (end of 2021), Firefox Devtools are already able to log nested stacktraces!

enter image description here

Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419
4

Joyent released a Node.js package that can be used exactly for that. It is called VError. I paste an example of how you would use the pacakge:

var fs = require('fs');
var filename = '/nonexistent';
fs.stat(filename, function (err1) {
    var err2 = new VError(err1, 'stat "%s"', filename);
    console.error(err2.message);
});

would print the following:

stat "/nonexistent": ENOENT, stat '/nonexistent'
eliocs
  • 18,511
  • 7
  • 40
  • 52
  • 3
    Please don't post identical answers to [multiple questions](http://stackoverflow.com/a/40287580). Post one good answer, then vote/flag to close the other questions as duplicates. If the question is not a duplicate, *tailor your answers to the question.* – Paul Roub Oct 27 '16 at 14:56
  • [@netflix/nerror](https://github.com/Netflix/nerror) is a more modern alternative to verror and has built-in types. – raythurnevoid Feb 08 '21 at 11:18
0

2021 Update: To chain exceptions in JS:

class MyAppError extends Error {
    constructor(...params) {
        super(...params)
        if (Error.captureStackTrace) {
            // This is the key line!
            Error.captureStackTrace(this, this.constructor);
        }
        this.name = this.constructor.name
    }
}

See the Mozilla docs on Error.captureStackTrace

Erin
  • 5,315
  • 2
  • 20
  • 36
-4

Use a try / catch block:

try {
    this.config = JSON.parse("}}junkJSON}");
    //...etc
}
catch (e) {
    //console.log(e.message);//the original error message 
    e.message = "Your config file is not well formatted.";//replace with new custom message
    console.error(e);//raise the exception in the console
    //or re-throw it without catching
    throw e;
}

http://jsfiddle.net/0ogf1jxs/5/

UPDATE: If you really feel the need for a custom error you can define your own:

function BadConfig(message) {
   this.message = message;
   this.name = "BadConfig";
}
BadConfig.prototype = new Error();
BadConfig.prototype.constructor = BadConfig;

try {
    this.config = JSON.parse("}}badJson}");
} catch(e) {
    throw new BadConfig("Your JSON is wack!");
}

http://jsfiddle.net/kL394boo/

Lots of useful info at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error

Moob
  • 14,420
  • 1
  • 34
  • 47
  • I wanted to "throw" something because I'm in library code, so I want the developer who uses it to be able to catch it and display it to the user in the way he wants... Actually I want to do something like passing the root cause to a new Exception in Java – Anthony O. Sep 10 '14 at 11:21
  • See: http://stackoverflow.com/questions/783818/how-do-i-create-a-custom-error-in-javascript – Moob Sep 10 '14 at 11:29
  • 1
    Just edit this one and change e.message to your user friendly message and throw e – Jonas Liljestrand Sep 10 '14 at 11:44
  • @JonasLiljestrand - Updated answer accordingly – Moob Sep 10 '14 at 11:53
  • 1
    Thank you for your answer but it still doesn't reply to my question which is: how to chain exceptions in JS like adding cause to an Exception in Java. Your `BadConfig` class doesn't include the catched `e` and can't display it as a cause in the error log if the one who catch the `BadConfig` output it in `console.error`. – Anthony O. Sep 10 '14 at 13:26
  • I must be misunderstanding your requirements. The `stack` is still available. See test here: http://jsfiddle.net/kL394boo/1/ – Moob Sep 10 '14 at 14:58