Alex028502
Alex028502

Reputation: 3814

nodejs: Error.captureStackTrace() adds stack, and I can access it, but I can't see it when I console log the error

here is a program I made called example.js

const e = {
  test: 'test',
};

console.log('object', e);
console.log('stack', e.stack);
console.log('now add stack trace info');
Error.captureStackTrace(e);
console.log('object', e);
console.log('stack', e.stack);

and when I run it, this is what I get:

pi@raspberrypi:~ $ node example.js 
object { test: 'test' }
stack undefined
now add stack trace info
object { test: 'test' }
stack Error
    at Object.<anonymous> (/home/pi/example.js:10:7)
    at Module._compile (internal/modules/cjs/loader.js:1137:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
    at Module.load (internal/modules/cjs/loader.js:985:32)
    at Function.Module._load (internal/modules/cjs/loader.js:878:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47
pi@raspberrypi:~ $ node --version
v12.18.3


so the stack property is added, and I can print it out individually, but it is hidden when I print the whole object.

When I console.log(JSON.stringify(e));, the stack field is still not visible.

How does that work? Where is that field hidden?

Upvotes: 1

Views: 1959

Answers (1)

Ouroborus
Ouroborus

Reputation: 16875

Short Answer

The stack property is set to be non-enumerable and so doesn't show up when the object's properties are enumerated as is done when using JSON.stringify.

Long Answer

Object properties consist of a number of descriptors that control their value and how the system interacts with them. These include:

configurable

  • true if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object. Defaults to false.

enumerable

  • true if and only if this property shows up during enumeration of the properties on the corresponding object. Defaults to false.

writable

  • true if the value associated with the property may be changed with an assignment operator. Defaults to false.

value

  • The value associated with the property. Can be any valid JavaScript value (number, object, function, etc). Defaults to undefined.

(There are also get and set as well as some configuration and behavioral rules but they're not important here. If you're interested, this is described on MDN under Object.defineProperty().)

Let's assume you have an object and you then assign to a previously non-existent property on that object:

const someObject = {};
someObject.someProperty = 'someValue';

This is similar to:

const someObject = {};
Object.defineProperty(someObject, 'someProperty', {
  configurable: true, 
  enumerable: true, 
  writable: true, 
  value: 'someValue',
});

When Error.captureStackTrace creates or updates the stack property on an object, it sets that property's enumerable descriptor to false. Because of this, JSON.stringify doesn't see the property when it enumerates over the object's properties.

Solution

After calling Error.captureStackTrace, update the stack property's descriptors using Object.defineProperty, as in:

Object.defineProperty(e, 'stack', { enumerable: true });

This will cause the property to be enumerable so that JSON.stringify can see it.

Upvotes: 4

Related Questions