Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Error.captureStackTrace and stack trace persistance?

I a while ago i used to use Verror from joyent to not lose the stacktrace when rethrowing, I have just done a test with node v12 without Verror and stack trace seems to be persisted without the use of error.

I then was looking at the use of Error.captureStackTrace, it states to use this in your errors so that the Error is not added to the stack.

I don't what i am doing wrong but with or without Error.captureStackTrace - the stack trace is the same..

I would like to know the current status of the use of the captureStackTrace as i see no difference :-) and also the use of VError that doesn't seem to be needed anymore.

In the documentation it states that the .stack isn't available without calling the captureStackTrace but I see it available each time, with or without the captureStackTrace

here is an example of 2 x errors

class MyErrorOne extends Error {
  constructor(message) {
    super(message);

    Error.captureStackTrace(this, this.constructor);
  }
}

class MyErrorTwo extends Error {
  constructor(message) {
    super(message);

    Error.captureStackTrace(this, this.constructor);
  }
}

I tried them by commenting out the captureStackTrace in EACH error and the stacktrace is the same.

Can anyone help ?

Here is my code to test calling the errors

const DoOne = () => {
  try {
    console.log("executing do one");
    DoTwo();
  } catch (error) {
    console.log("error in DoOne", error);
    console.log("here is the stack ", error.stack);
    throw new MyErrorOne("threw error from doone in myerrorone");
    // throw error;
  }
};

const DoTwo = () => {
  try {
    console.log("executing do two");
    throw new MyErrorTwo("threw error from dotwo in myerrortwo");
  } catch (error) {
    console.log("error in DoTwo", error);
    throw error;
  }
};

DoOne();
like image 625
Martin Avatar asked Sep 03 '25 03:09

Martin


2 Answers

When calling Error.captureStackTrace(obj[, fun]) a formatted call stack is attached to obj including the line/frame where captureStackTrace was called.

When specifying fun all frames above and including fun are removed.

Examples:

Note: In sample outputs I have removed anything below call to fun1 to minimize clutter.

const fun1 = () => { fun2(); };
const fun2 = () => { fun3(); };
const fun3 = () => { log_stack(); };
function log_stack() {
    let err = {};
    Error.captureStackTrace(err);
    console.log(err.stack);
}
fun1();

This yields:

Error
    at log_stack (/path/to/example.js:6:8)
    at fun3 (/path/to/example.js:3:22)
    at fun2 (/path/to/example.js:2:22)
    at fun1 (/path/to/example.js:1:22)

Now, if we add log_stack as the function option to captureStackTrace:

Error.captureStackTrace(err, log_stack);

It yields:

Error
    at fun3 (/path/to/example.js:3:22)
    at fun2 (/path/to/example.js:2:22)
    at fun1 (/path/to/example.js:1:22)

The log_stack frame is not there anymore.

Adding fun3 to the captureStackTrace:

Error.captureStackTrace(err, fun3);

It yields:

Error
    at fun2 (/path/to/example.js:2:22)
    at fun1 (/path/to/example.js:1:22)

Etc.

In your case, if you change:

Error.captureStackTrace(this, this.constructor);

to:

Error.captureStackTrace(this);

You will see that you get an additional line with the new MyError...:

error in DoTwo MyErrorTwo: threw error from dotwo in myerrortwo
    at new MyErrorTwo (/path/to/testerrorclass.js:10:9)  <<== Not removed anymore.
like image 134
user3342816 Avatar answered Sep 06 '25 03:09

user3342816


I'm not sure, but it seems that Error.captureStackTrace is intended to be used when constructing Error object without extending the Error class (see also the example provided in the Node docs.

I'm guessing that when you're extending the Error class, capturing the stack trace is already done by the Error constructor.

I've tested your code and remove the extending of Error and indeed if you don't call captureStackTrace you will not get a stack trace on your error objects.

I'm not sure what would be the use case of throwing Errors that are not extending the Error class.

like image 41
yuvke Avatar answered Sep 06 '25 04:09

yuvke