modern-errors
plugin to serialize/parse
errors.
This adds BaseError.serialize()
and
BaseError.parse()
to serialize/parse errors
to/from plain objects.
- Ensures errors are safe to serialize with JSON
- Deep serialization/parsing
- Custom serialization/parsing (e.g. YAML or
process.send()
) - Keeps error classes
- Preserves errors' additional properties
- Works recursively with
AggregateError
- Safe: this never throws
Adding the plugin to
modern-errors
.
import ModernError from 'modern-errors'
import modernErrorsSerialize from 'modern-errors-serialize'
export const BaseError = ModernError.subclass('BaseError', {
plugins: [modernErrorsSerialize],
})
// ...
Serializing errors to plain objects.
const error = new ExampleError('message', { props: { filePath } })
const errorObject = BaseError.serialize(error)
// { name: 'ExampleError', message: 'message', stack: '...', filePath: '...' }
const errorString = JSON.stringify(errorObject)
// '{"name":"ExampleError",...}'
Parsing errors from plain objects.
const newErrorObject = JSON.parse(errorString)
const newError = BaseError.parse(newErrorObject)
// ExampleError: message
// at ...
// filePath: '...'
npm install modern-errors-serialize
This package works in both Node.js >=14.18.0 and
browsers.
It is an ES module and must be loaded using
an import
or import()
statement,
not require()
.
Type: Plugin
Plugin object to pass to the
plugins
option of
ErrorClass.subclass()
.
error
: ErrorInstance
Return value: ErrorObject
Converts error
to an error plain object. All
error properties
are kept.
Plugin options are
also preserved.
errorObject
: ErrorObject
Return value: ErrorInstance
Converts errorObject
to an error instance. The original error classes are
preserved providing they are
subclasses of
BaseError
.
Type: object
Type: boolean
Default: false
Unless this option is true
, nested errors are also serialized/parsed. They can
be inside other errors, plain objects or arrays.
const inner = new ExampleError('inner')
const error = new ExampleError('example', { props: { inner } })
BaseError.serialize(error).inner // { name: 'BaseError', message: 'inner', ... }
BaseError.serialize(error, { shallow: true }).inner // BaseError
const errorObject = BaseError.serialize(error)
BaseError.parse(errorObject).inner // BaseError
BaseError.parse(errorObject, { shallow: true }).inner // { name: '...', ... }
Type: boolean
Default: false
By default, when the argument is not an Error
instance or an error plain
object, it is converted to one. If this option is true
, it is kept as is
instead.
BaseError.serialize('example') // { name: 'BaseError', message: 'example', ... }
BaseError.serialize('example', { loose: true }) // 'example'
BaseError.parse('example') // BaseError
BaseError.parse('example', { loose: true }) // 'example'
Options can apply to (in priority order):
- Any error: second argument to
ModernError.subclass()
export const BaseError = ModernError.subclass('BaseError', {
plugins: [modernErrorsSerialize],
serialize: options,
})
- Any error of a specific class (and its subclasses): second argument to
ErrorClass.subclass()
export const ExampleError = BaseError.subclass('ExampleError', {
serialize: options,
})
- A specific error: second argument to
new ErrorClass()
throw new ExampleError('...', { serialize: options })
- A specific
BaseError.serialize(error)
orBaseError.parse(errorObject)
call
BaseError.serialize(error, options)
BaseError.parse(errorObject, options)
Error plain objects are always safe to serialize with JSON.
const error = new ExampleError('message')
error.cycle = error
// Cycles make `JSON.stringify()` throw, so they are removed
console.log(BaseError.serialize(error).cycle) // undefined
The loose
option can be used to deeply serialize/parse objects and
arrays.
const error = new ExampleError('message')
const deepArray = BaseError.serialize([{}, { error }], { loose: true })
const jsonString = JSON.stringify(deepArray)
const newDeepArray = JSON.parse(jsonString)
const newError = BaseError.parse(newDeepArray, { loose: true })[1].error
// ExampleError: message
// at ...
error.toJSON()
is defined. It is automatically called by
JSON.stringify()
.
const error = new ExampleError('message')
const deepArray = [{}, { error }]
const jsonString = JSON.stringify(deepArray)
const newDeepArray = JSON.parse(jsonString)
const newError = BaseError.parse(newDeepArray, { loose: true })[1].error
// ExampleError: message
// at ...
Errors are converted to/from plain objects, not strings. This allows any serialization/parsing logic to be performed.
import { dump, load } from 'js-yaml'
const error = new ExampleError('message')
const errorObject = BaseError.serialize(error)
const errorYamlString = dump(errorObject)
// name: ExampleError
// message: message
// stack: ExampleError: message ...
const newErrorObject = load(errorYamlString)
const newError = BaseError.parse(newErrorObject) // ExampleError: message
const error = new ExampleError('message', { props: { prop: true } })
const errorObject = BaseError.serialize(error)
console.log(errorObject.prop) // true
const newError = BaseError.parse(errorObject)
console.log(newError.prop) // true
const error = new ExampleError('message', {
errors: [new ExampleError('one'), new ExampleError('two')],
})
const errorObject = BaseError.serialize(error)
// {
// name: 'ExampleError',
// message: 'message',
// stack: '...',
// errors: [{ name: 'ExampleError', message: 'one', stack: '...' }, ...],
// }
const newError = BaseError.parse(errorObject)
// ExampleError: message
// [errors]: [ExampleError: one, ExampleError: two]
If an error with a
custom
class is
parsed, its custom constructor is not called. However, any property previously
set by that constructor is still preserved, providing it is serializable and
enumerable.
const ExampleError = BaseError.subclass('ExampleError', {
custom: class extends BaseError {
constructor(message, options, prop) {
super(message, options, prop)
this.prop = prop
}
},
})
const error = new ExampleError('message', {}, true)
const errorObject = BaseError.serialize(error)
// `constructor(message, options, prop)` is not called
const newError = BaseError.parse(errorObject)
// But properties set by that `constructor(...)` are kept
console.log(newError.prop) // true
error-serializer
: Convert errors to/from plain objectsmodern-errors
: Handle errors like it's 2022 🔮modern-errors-cli
: Handle errors in CLI modulesmodern-errors-process
: Handle process errorsmodern-errors-bugs
: Print where to report bugsmodern-errors-clean
: Clean stack tracesmodern-errors-http
: Create HTTP error responsesmodern-errors-winston
: Log errors with Winston
For any question, don't hesitate to submit an issue on GitHub.
Everyone is welcome regardless of personal background. We enforce a Code of conduct in order to promote a positive and inclusive environment.
This project was made with ❤️. The simplest way to give back is by starring and sharing it online.
If the documentation is unclear or has a typo, please click on the page's Edit
button (pencil icon) and suggest a correction.
If you would like to help us fix a bug or add a new feature, please check our guidelines. Pull requests are welcome!