1

I have an error object which has several properties and looks like this in the console:

object props

But JSON.stringify(event) only results in the string '{"isTrusted":true}, which omits all the important properties I'm looking for.

I've searched for and tried several solutions but none seem to give the expected result:

1.

> JSON.stringify(event, Object.getOwnPropertyNames(event)) < '{"isTrusted":true}' 
> JSON.stringify(event, (function(seen, k, value) { console.log(`k=${k} value=${value}`); if (typeof value === 'object' && value !== null) { if (seen.indexOf(value) !== -1) return; else seen.push(value); } return value; }).bind(null, [])); < '{"isTrusted":true}' 
> for(k in event){ console.log(k); } < undefined 
> event.toString() < '[object ErrorEvent]' 
> Object.keys(event) < ['isTrusted'] 

The only thing that seems to work is manually listing the property names I see in the console, and passing that to JSON.stringy as an array explicity:

JSON.stringify(event, ["isTrusted", "bubbles", "cancelBubble", "cancelable", "colno", "composed", "currentTarget", "defaultPrevented", "error", "eventPhase", "filename", "lineno", "message", "returnValue", "srcElement", "target", "timeStamp", "type"]) '{"isTrusted":true,"bubbles":false,"cancelBubble":false,"cancelable":true,"colno":5,"composed":false,"currentTarget":{},"defaultPrevented":false,"error":"{\\"reason\\":\\"GET /problem/8a9463a241657d960a68ca73f2a532f3 failed: 500\\"}","eventPhase":2,"filename":"http://localhost:3000/js/chess.js","lineno":26,"message":"Uncaught {\\"reason\\":\\"GET /problem/8a9463a241657d960a68ca73f2a532f3 failed: 500\\"}","returnValue":true,"srcElement":{},"target":{},"timeStamp":168.59999999403954,"type":"error"}' 

Doing this feels wrong and I could miss properties that are not in the static list above.

How can I enumerate the same set of object properties I can see in the console?

1 Answer 1

5

You're trying to serialize an ErrorEvent object, but the issue is that ErrorEvent properties are defined as getters on the prototype, not as own properties of the instance. That's why Object.keys(), for...in, and JSON.stringify() don't find them.

The correct way is to iterate over the prototype chain using Object.getOwnPropertyNames():

function getEventProperties(event) { const props = {}; let obj = event; while (obj !== null && obj !== Object.prototype) { Object.getOwnPropertyNames(obj).forEach(prop => { if (!(prop in props) && typeof event[prop] !== 'function') { try { props[prop] = event[prop]; } catch (e) { // Some properties might throw when accessed } } }); obj = Object.getPrototypeOf(obj); } return props; } const allProps = getEventProperties(event); console.log(JSON.stringify(allProps, null, 2)); 

but if you only need ErrorEvent specific properties without inherited Event properties...

const errorEventProps = Object.getOwnPropertyNames(ErrorEvent.prototype) .filter(prop => prop !== 'constructor') .reduce((acc, prop) => { acc[prop] = event[prop]; return acc; }, {}); console.log(JSON.stringify(errorEventProps, null, 2)); 

Or more directly, combine properties from both ErrorEvent and Event like this

const allEventProps = [ ...Object.getOwnPropertyNames(ErrorEvent.prototype), ...Object.getOwnPropertyNames(Event.prototype) ].filter(prop => prop !== 'constructor' && typeof event[prop] !== 'function'); console.log(JSON.stringify(event, allEventProps, 2)); 

Why your code didn't work is because Object.getOwnPropertyNames(event) only gets properties on the instance itself, not from the prototype where ErrorEvent defines message, filename, lineno, etc.

Sign up to request clarification or add additional context in comments.

5 Comments

This enumerates most fields but I notice "reason" is missing. And "reason" is a pretty important field. Any idea why?
hello, sorry for reply late. let me review the code again and check my answer to give you a good answer for your question.
I'm getting these events by setting window.onunhandledrejection: window.onunhandledrejection = event => { const string = stringifyError(event); reportError(string); }; They seem to trigger when a promise or async function throws an exception. I used your third approach: const allEventProps = [ ...Object.getOwnPropertyNames(ErrorEvent.prototype), ...Object.getOwnPropertyNames(Event.prototype) ].filter(prop => prop !== 'constructor' && typeof event[prop] !== 'function'); I haven't checked if using other approaches we do get the reason and stack pro
Or just use the first approach that walks the whole prototype chain, that one also works for any event ype regardless. do you want me to add it into my full answer? i can edit that answer if you want me to.
well, i reviewed and the problem is that your are capturing a PromiseRejectionEvent with window.onunhandledrejection not an ErrorEvent my friend. They basicallly diferent objects and reason is defined in PromiseRejectionEvent.prototype so thats why is not showing up. in this case change ErrorEvent.prototype to PromiseRejectionEvent.prototype in the thir approach and it should work.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.