I\'m running into an issue when trying to pass error messages around using web sockets. I can replicate the issue I am facing using J
I was working on a JSON format for log appenders and ended up here trying to solve a similar problem. After a while, I realized I could just make Node do the work:
const util = require("util");
...
return JSON.stringify(obj, (name, value) => {
if (value instanceof Error) {
return util.format(value);
} else {
return value;
}
}
You can solve this with a one-liner( errStringified ) in plain javascript:
var error = new Error('simple error message');
var errStringified = (err => JSON.stringify(Object.getOwnPropertyNames(Object.getPrototypeOf(err)).reduce(function(accumulator, currentValue) { return accumulator[currentValue] = err[currentValue], accumulator}, {})))(error);
console.log(errStringified);
It works with DOMExceptions as well.
There is a great Node.js package for that: serialize-error
.
npm install serialize-error
It handles well even nested Error objects.
import {serializeError} from 'serialize-error';
JSON.stringify(serializeError(error));
Docs: https://www.npmjs.com/package/serialize-error
None of the answers above seemed to properly serialize properties which are on the prototype of Error (because getOwnPropertyNames()
does not include inherited properties). I was also not able to redefine the properties like one of the answers suggested.
This is the solution I came up with - it uses lodash but you could replace lodash with generic versions of those functions.
function recursivePropertyFinder(obj){
if( obj === Object.prototype){
return {};
}else{
return _.reduce(Object.getOwnPropertyNames(obj),
function copy(result, value, key) {
if( !_.isFunction(obj[value])){
if( _.isObject(obj[value])){
result[value] = recursivePropertyFinder(obj[value]);
}else{
result[value] = obj[value];
}
}
return result;
}, recursivePropertyFinder(Object.getPrototypeOf(obj)));
}
}
Error.prototype.toJSON = function(){
return recursivePropertyFinder(this);
}
Here's the test I did in Chrome:
var myError = Error('hello');
myError.causedBy = Error('error2');
myError.causedBy.causedBy = Error('error3');
myError.causedBy.causedBy.displayed = true;
JSON.stringify(myError);
{"name":"Error","message":"hello","stack":"Error: hello\n at <anonymous>:66:15","causedBy":{"name":"Error","message":"error2","stack":"Error: error2\n at <anonymous>:67:20","causedBy":{"name":"Error","message":"error3","stack":"Error: error3\n at <anonymous>:68:29","displayed":true}}}
Make it serializable
// example error
let err = new Error('I errored')
// one liner converting Error into regular object that can be stringified
err = Object.getOwnPropertyNames(err).reduce((acc, key) => { acc[key] = err[key]; return acc; }, {})
If you want to send this object from child process, worker or though the network there's no need to stringify. It will be automatically stringified and parsed like any other normal object