21

Is there a preferred way to include inner exceptions when throwing exceptions in JavaScript?

I'm relatively new to JavaScript coming from a C# background. In C#, you can do the following:

try 
{
  // Do stuff
}
catch (Exception ex)
{
  throw new Exception("This is a more detailed message.", ex);
}

In the samples I've seen in JavaScript, I haven't been able to find how to catch an exception, add a new message, and re-throw the new exception while still passing the original exception.

3
  • 2
    You can define your own exceptions in javascript: stackoverflow.com/a/464500/1291428 . Then, the concept is somewhat a global standard: the exception should be appropriate to whom is consuming your api. So, it means catching it if necessary, adding following information, logging the original exception etc. Refer to Joshua Bloch, Effective Java 2nd Edition, Item 61: Throw exceptions appropriate to the abstraction
    – Sebas
    Commented Oct 29, 2014 at 20:28
  • I see. I thought there was maybe a way this is typically handled to make it easy for the consumer of the API. I'll probably just add a field called innerException to a custom exception. Thanks! Commented Oct 29, 2014 at 20:33
  • throw reveals a stack, so you should be able to trace exactly where the problem lays. that said, stack is not a standard property, though it is, in a few slightly different formats, widely-implimented.
    – dandavis
    Commented Oct 29, 2014 at 20:48

2 Answers 2

10

You can throw any object you want:

try {
    var x = 1/0; 
}
catch (e) {
    throw new MyException("There is no joy in Mudville", e);
}

function MyException(text, internal_exception) {
    this.text = text;
    this.internal_exception = internal_exception;
}

Then an error will be thrown of type MyException with properties text and internal_exception.

2
  • I do it like this with the addition that besides "text" and "internalError" I also have a dynamic property "data", an object where I log various info, sometimes related to the input that generated the error. I do it like that for easier and more detailed debugging.
    – Vee6
    Commented Apr 9, 2018 at 19:53
  • 4
    Throwing any object is a bad idea though because (to my knowledge) only the Error type can be used to correctly get the stack/stackTrace at the point of the first-throw. So rather than having function MyException instead have class MyError extends Error.
    – Dai
    Commented Sep 11, 2021 at 4:53
4

An inner error may be available in the Error.cause property. You may provide one via the options parameter of the Error constructor. Example:

try {
  divide(dividend, divisor);
} catch (err) {
  throw new Error(`Devision by ${divisor} failed. See cause for details.`, { cause: err });
}

When such an error is thrown and printed, it will show the inner errors recursivly, just as you'd expect. Running throw new Error("Outer", { cause: new Error("Inner") }); in ts-node REPL produces:

Uncaught Error: Outer
    at <repl>.ts:1:7
    at Script.runInThisContext (node:vm:129:12)
    ... 7 lines matching cause stack trace ...
    at bound (node:domain:433:15) {
  [cause]: Error: Inner
      at <repl>.ts:1:35
      at Script.runInThisContext (node:vm:129:12)
      at runInContext (/usr/local/lib/node_modules/ts-node/src/repl.ts:665:19)
      at Object.execCommand (/usr/local/lib/node_modules/ts-node/src/repl.ts:631:28)
      at /usr/local/lib/node_modules/ts-node/src/repl.ts:653:47
      at Array.reduce (<anonymous>)
      at appendCompileAndEvalInput (/usr/local/lib/node_modules/ts-node/src/repl.ts:653:23)
      at evalCodeInternal (/usr/local/lib/node_modules/ts-node/src/repl.ts:221:12)
      at REPLServer.nodeEval (/usr/local/lib/node_modules/ts-node/src/repl.ts:243:26)
      at bound (node:domain:433:15)

Note that it's only a convention to put the inner error inside cause (but a strong one, as seen from ts-node truncating the outer stack trace due to 7 lines matching cause stack trace). So anything may be inside the cause property, so check it before you consume it! MDN gives an example of putting additional data after the example of using it for an inner error:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.