{"id":16208479,"url":"https://github.com/ehmicky/error-serializer","last_synced_at":"2025-03-16T11:30:37.166Z","repository":{"id":56797094,"uuid":"524761646","full_name":"ehmicky/error-serializer","owner":"ehmicky","description":"Convert errors to/from plain objects.","archived":false,"fork":false,"pushed_at":"2025-03-13T05:04:08.000Z","size":3413,"stargazers_count":16,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-13T06:19:08.756Z","etag":null,"topics":["convert","error","error-handling","error-monitoring","error-reporting","errors","exception-handling","javascript","json","library","message","monitoring","nodejs","normalization","object","parsing","serialization","serializer","stacktrace","typescript"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ehmicky.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-14T19:29:13.000Z","updated_at":"2025-03-13T05:04:12.000Z","dependencies_parsed_at":"2023-02-18T17:45:33.390Z","dependency_job_id":"6bf58233-df58-4fba-bca2-723b694554f2","html_url":"https://github.com/ehmicky/error-serializer","commit_stats":{"total_commits":463,"total_committers":4,"mean_commits":115.75,"dds":"0.015118790496760237","last_synced_commit":"bac31f79a4d67dfa9b1c23ba16d3ff6ab337aa66"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":"ehmicky/template-javascript","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehmicky%2Ferror-serializer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehmicky%2Ferror-serializer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehmicky%2Ferror-serializer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehmicky%2Ferror-serializer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ehmicky","download_url":"https://codeload.github.com/ehmicky/error-serializer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243814907,"owners_count":20352037,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["convert","error","error-handling","error-monitoring","error-reporting","errors","exception-handling","javascript","json","library","message","monitoring","nodejs","normalization","object","parsing","serialization","serializer","stacktrace","typescript"],"created_at":"2024-10-10T10:17:12.118Z","updated_at":"2025-03-16T11:30:37.107Z","avatar_url":"https://github.com/ehmicky.png","language":"JavaScript","readme":"[![Node](https://img.shields.io/badge/-Node.js-808080?logo=node.js\u0026colorA=404040\u0026logoColor=66cc33)](https://www.npmjs.com/package/error-serializer)\n[![Browsers](https://img.shields.io/badge/-Browsers-808080?logo=firefox\u0026colorA=404040)](https://unpkg.com/error-serializer?module)\n[![TypeScript](https://img.shields.io/badge/-Typed-808080?logo=typescript\u0026colorA=404040\u0026logoColor=0096ff)](/src/main.d.ts)\n[![Codecov](https://img.shields.io/badge/-Tested%20100%25-808080?logo=codecov\u0026colorA=404040)](https://codecov.io/gh/ehmicky/error-serializer)\n[![Minified size](https://img.shields.io/bundlephobia/minzip/error-serializer?label\u0026colorA=404040\u0026colorB=808080\u0026logo=webpack)](https://bundlephobia.com/package/error-serializer)\n[![Mastodon](https://img.shields.io/badge/-Mastodon-808080.svg?logo=mastodon\u0026colorA=404040\u0026logoColor=9590F9)](https://fosstodon.org/@ehmicky)\n[![Medium](https://img.shields.io/badge/-Medium-808080.svg?logo=medium\u0026colorA=404040)](https://medium.com/@ehmicky)\n\nConvert errors to/from plain objects.\n\n# Hire me\n\nPlease\n[reach out](https://www.linkedin.com/feed/update/urn:li:activity:7117265228068716545/)\nif you're looking for a Node.js API or CLI engineer (11 years of experience).\nMost recently I have been [Netlify Build](https://github.com/netlify/build)'s\nand [Netlify Plugins](https://www.netlify.com/products/build/plugins/)'\ntechnical lead for 2.5 years. I am available for full-time remote positions.\n\n# Features\n\n- Ensures errors are [safe to serialize with JSON](#json-safety)\n- Can be used as [`error.toJSON()`](#errortojson)\n- [Deep serialization/parsing](#deep-serializationparsing), including\n  [transforming](#transforming)\n- [Custom serialization/parsing](#custom-serializationparsing) (e.g. YAML or\n  `process.send()`)\n- Keeps both native (`TypeError`, etc.) and [custom](#classes) error classes\n- Preserves errors' [additional properties](#additional-error-properties)\n- Can keep [constructor's arguments](#constructors)\n- Works [recursively](#errorcause-and-aggregateerror) with\n  [`error.cause`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause)\n  and\n  [`AggregateError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError)\n- [Normalizes](#loose) invalid errors\n- Safe: this never throws\n\n# Example\n\n```js\nimport { parse, serialize } from 'error-serializer'\n\nconst error = new TypeError('example')\nconst errorObject = serialize(error)\n// Plain object: { name: 'TypeError', message: 'example', stack: '...' }\n\nconst errorString = JSON.stringify(errorObject)\nconst newErrorObject = JSON.parse(errorString)\n\nconst newError = parse(newErrorObject)\n// Error instance: 'TypeError: example ...'\n```\n\n# Install\n\n```bash\nnpm install error-serializer\n```\n\nThis package works in both Node.js \u003e=18.18.0 and\n[browsers](https://raw.githubusercontent.com/ehmicky/dev-tasks/main/src/browserslist).\n\nThis is an ES module. It must be loaded using\n[an `import` or `import()` statement](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c),\nnot `require()`. If TypeScript is used, it must be configured to\n[output ES modules](https://www.typescriptlang.org/docs/handbook/esm-node.html),\nnot CommonJS.\n\n# API\n\n## serialize(errorInstance, options?)\n\n`errorInstance` `any`\\\n`options` [`Options?`](#options)\\\n_Return value_: `ErrorObject`\n\nConvert an `Error` instance into a plain object.\n\n### Options\n\nObject with the following optional properties.\n\n#### shallow\n\n_Type_: `boolean`\\\n_Default_: `false`\n\nUnless this option is `true`, nested errors are also serialized. They can be\ninside other errors, plain objects or arrays.\n\n\u003c!-- eslint-disable no-unused-expressions --\u003e\n\n```js\nconst error = new Error('example')\nerror.inner = new Error('inner')\nserialize(error).inner // { name: 'Error', message: 'inner', ... }\nserialize(error, { shallow: true }).inner // Error: inner ...\n```\n\n#### loose\n\n_Type_: `boolean`\\\n_Default_: `false`\n\nBy default, when the argument is not an `Error` instance, it is converted to\none. If this option is `true`, it is kept as is instead.\n\n```js\nserialize('example') // { name: 'Error', message: 'example', ... }\nserialize('example', { loose: true }) // 'example'\n```\n\n#### include\n\n_Type_: `string[]`\n\nOnly pick [specific properties](#omit-additional-error-properties).\n\n```js\nserialize(error, { include: ['message'] }) // { message: 'example' }\n```\n\n#### exclude\n\n_Type_: `string[]`\n\nOmit [specific properties](#omit-stack-traces).\n\n```js\nserialize(error, { exclude: ['stack'] }) // { name: 'Error', message: 'example' }\n```\n\n#### transformObject(errorObject, errorInstance)\n\n_Type_: `(errorObject, errorInstance) =\u003e void`\n\n[Transform](#transforming) each error plain object.\n\n`errorObject` is the error after serialization. It must be directly mutated.\n\n`errorInstance` is the error before serialization.\n\n## parse(errorObject, options?)\n\n`errorObject` `any`\\\n`options` [`Options?`](#options)\\\n_Return value_: `Error`\n\nConvert an error plain object into an `Error` instance.\n\n### Options\n\nObject with the following optional properties.\n\n#### classes\n\n_Type_: `object`\n\nCustom error classes to keep when parsing.\n\n- Each key is an `errorObject.name`\n- Each value is the error class to use\n\n```js\nconst errorObject = serialize(new CustomError('example'))\n// `CustomError` class is kept\nconst error = parse(errorObject, { classes: { CustomError } })\n// Map `CustomError` to another class\nconst otherError = parse(errorObject, { classes: { CustomError: TypeError } })\n```\n\n#### shallow\n\n_Type_: `boolean`\\\n_Default_: `false`\n\nUnless this option is `true`, nested error plain objects are also parsed. They\ncan be inside other errors, plain objects or arrays.\n\n\u003c!-- eslint-disable no-unused-expressions --\u003e\n\n```js\nconst error = new Error('example')\nerror.inner = new Error('inner')\nconst errorObject = serialize(error)\n\nparse(errorObject).inner // Error: inner ...\nparse(errorObject, { shallow: true }).inner // { name: 'Error', message: ... }\n```\n\n#### loose\n\n_Type_: `boolean`\\\n_Default_: `false`\n\nBy default, when the argument is not an error plain object, it is converted to\none. If this option is `true`, it is kept as is instead.\n\n```js\nparse('example') // Error: example\nparse('example', { loose: true }) // 'example'\n```\n\n#### transformArgs(constructorArgs, errorObject, ErrorClass)\n\n_Type_: `(constructorArgs, errorObject, ErrorClass) =\u003e void`\n\n[Transform](#transforming) the arguments passed to each `new Error()`.\n\n`constructorArgs` is the array of arguments. Usually, `constructorArgs[0]` is\nthe\n[error message](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/message)\nand `constructorArgs[1]` is the\n[constructor options object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Error#parameters).\n`constructorArgs` must be directly mutated.\n\n`errorObject` is the error before parsing. `ErrorClass` is its\n[class](#classes).\n\n#### transformInstance(errorInstance, errorObject)\n\n_Type_: `(errorInstance, errorObject) =\u003e void`\n\n[Transform](#transforming) each `Error` instance.\n\n`errorInstance` is the error after parsing. It must be directly mutated.\n\n`errorObject` is the error before parsing.\n\n# Usage\n\n## JSON safety\n\nError plain objects are always\n[safe to serialize with JSON](https://github.com/ehmicky/safe-json-value).\n\n\u003c!-- eslint-disable no-unused-expressions --\u003e\n\n```js\nconst error = new Error('example')\nerror.cycle = error\n\n// Cycles make `JSON.stringify()` throw, so they are removed\nserialize(error).cycle // undefined\n```\n\n## `error.toJSON()`\n\n[`serialize()`](#serializeerrorinstance-options) can be used as\n[`error.toJSON()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#tojson_behavior).\n\n\u003c!-- eslint-disable fp/no-class, fp/no-this --\u003e\n\n```js\nclass CustomError extends Error {\n  /* constructor(...) { ... } */\n\n  toJSON() {\n    return serialize(this)\n  }\n}\nconst error = new CustomError('example')\n\nerror.toJSON()\n// { name: 'CustomError', message: 'example', stack: '...' }\nJSON.stringify(error)\n// '{\"name\":\"CustomError\",\"message\":\"example\",\"stack\":\"...\"}'\n```\n\n## Custom serialization/parsing\n\nErrors are converted to/from plain objects, not strings. This allows any\nserialization/parsing logic to be performed.\n\n```js\nimport { dump, load } from 'js-yaml'\n\nconst error = new Error('example')\nconst errorObject = serialize(error)\nconst errorYamlString = dump(errorObject)\n// name: Error\n// message: example\n// stack: Error: example ...\nconst newErrorObject = load(errorYamlString)\nconst newError = parse(newErrorObject) // Error: example\n```\n\n## Additional error properties\n\n```js\nconst error = new TypeError('example')\nerror.prop = true\n\nconst errorObject = serialize(error)\nconsole.log(errorObject.prop) // true\nconst newError = parse(errorObject)\nconsole.log(newError.prop) // true\n```\n\n## Omit additional error properties\n\n```js\nconst error = new Error('example')\nerror.prop = true\n\nconst errorObject = serialize(error, { include: ['name', 'message', 'stack'] })\nconsole.log(errorObject.prop) // undefined\nconsole.log(errorObject) // { name: 'Error', message: 'example', stack: '...' }\n```\n\n## Omit stack traces\n\n```js\nconst error = new Error('example')\n\nconst errorObject = serialize(error, { exclude: ['stack'] })\nconsole.log(errorObject.stack) // undefined\nconsole.log(errorObject) // { name: 'Error', message: 'example' }\n```\n\n## Deep serialization/parsing\n\nThe [`loose` option](#loose) can be used to deeply serialize/parse objects and\narrays.\n\n```js\nconst error = new Error('example')\nconst deepArray = serialize([{}, { error }], { loose: true })\n\nconst jsonString = JSON.stringify(deepArray)\nconst newDeepArray = JSON.parse(jsonString)\n\nconst newError = parse(newDeepArray, { loose: true })[1].error // Error: example\n```\n\n## Transforming\n\n\u003c!-- eslint-disable fp/no-mutation, no-param-reassign --\u003e\n\n```js\nconst errors = [new Error('test secret')]\nerrors[0].date = new Date()\n\nconst errorObjects = serialize(errors, {\n  loose: true,\n  // Serialize `Date` instances as strings\n  transformObject: (errorObject) =\u003e {\n    errorObject.date = errorObject.date.toString()\n  },\n})\nconsole.log(errorObjects[0].date) // Date string\n\nconst newErrors = parse(errorObjects, {\n  loose: true,\n  // Transform error message\n  transformArgs: (constructorArgs) =\u003e {\n    constructorArgs[0] = constructorArgs[0].replace('secret', '***')\n  },\n  // Parse date strings as `Date` instances\n  transformInstance: (error) =\u003e {\n    error.date = new Date(error.date)\n  },\n})\nconsole.log(newErrors[0].message) // 'test ***'\nconsole.log(newErrors[0].date) // `Date` instance\n```\n\n## `error.cause` and `AggregateError`\n\n```js\nconst innerErrors = [new Error('one'), new Error('two')]\nconst cause = new Error('three')\nconst error = new AggregateError(innerErrors, 'four', { cause })\n\nconst errorObject = serialize(error)\n// {\n//   name: 'AggregateError',\n//   message: 'four',\n//   stack: '...',\n//   cause: { name: 'Error', message: 'three', stack: '...' },\n//   errors: [{ name: 'Error', message: 'one', stack: '...' }, ...],\n// }\nconst newError = parse(errorObject)\n// AggregateError: four\n//   [cause]: Error: three\n//   [errors]: [Error: one, Error: two]\n```\n\n## Constructors\n\nBy default, when an error with custom [`classes`](#classes) is parsed, its\nconstructor is not called. In most cases, this is not a problem since any\nproperty previously set by that constructor is still preserved, providing it is\nserializable and enumerable.\n\nHowever, the `error.constructorArgs` property can be set to call the constructor\nwith those arguments. It it throws, `Error` will be used as a fallback error\nclass.\n\n\u003c!-- eslint-disable fp/no-class, fp/no-this, fp/no-mutation --\u003e\n\n```js\nclass CustomError extends Error {\n  constructor(prefix, message) {\n    super(`${prefix} - ${message}`)\n    this.constructorArgs = [prefix, message]\n  }\n}\nCustomError.prototype.name = 'CustomError'\n\nconst error = new CustomError('Prefix', 'example')\n\nconst errorObject = serialize(error)\n// This calls `new CustomError('Prefix', 'example')`\nconst newError = parse(errorObject, { classes: { CustomError } })\n```\n\n# Related projects\n\n- [`modern-errors`](https://github.com/ehmicky/modern-errors): Handle errors in\n  a simple, stable, consistent way\n- [`modern-errors-serialize`](https://github.com/ehmicky/modern-errors-serialize):\n  Serialize/parse errors\n- [`error-custom-class`](https://github.com/ehmicky/error-custom-class): Create\n  one error class\n- [`error-class-utils`](https://github.com/ehmicky/error-class-utils): Utilities\n  to properly create error classes\n- [`normalize-exception`](https://github.com/ehmicky/normalize-exception):\n  Normalize exceptions/errors\n- [`is-error-instance`](https://github.com/ehmicky/is-error-instance): Check if\n  a value is an `Error` instance\n- [`merge-error-cause`](https://github.com/ehmicky/merge-error-cause): Merge an\n  error with its `cause`\n- [`set-error-class`](https://github.com/ehmicky/set-error-class): Properly\n  update an error's class\n- [`set-error-message`](https://github.com/ehmicky/set-error-message): Properly\n  update an error's message\n- [`wrap-error-message`](https://github.com/ehmicky/wrap-error-message):\n  Properly wrap an error's message\n- [`set-error-props`](https://github.com/ehmicky/set-error-props): Properly\n  update an error's properties\n- [`set-error-stack`](https://github.com/ehmicky/set-error-stack): Properly\n  update an error's stack\n- [`error-cause-polyfill`](https://github.com/ehmicky/error-cause-polyfill):\n  Polyfill `error.cause`\n- [`handle-cli-error`](https://github.com/ehmicky/handle-cli-error): 💣 Error\n  handler for CLI applications 💥\n- [`safe-json-value`](https://github.com/ehmicky/safe-json-value): ⛑️ JSON\n  serialization should never fail\n- [`log-process-errors`](https://github.com/ehmicky/log-process-errors): Show\n  some ❤ to Node.js process errors\n- [`error-http-response`](https://github.com/ehmicky/error-http-response):\n  Create HTTP error responses\n- [`winston-error-format`](https://github.com/ehmicky/winston-error-format): Log\n  errors with Winston\n\n# Support\n\nFor any question, _don't hesitate_ to [submit an issue on GitHub](../../issues).\n\nEveryone is welcome regardless of personal background. We enforce a\n[Code of conduct](CODE_OF_CONDUCT.md) in order to promote a positive and\ninclusive environment.\n\n# Contributing\n\nThis project was made with ❤️. The simplest way to give back is by starring and\nsharing it online.\n\nIf the documentation is unclear or has a typo, please click on the page's `Edit`\nbutton (pencil icon) and suggest a correction.\n\nIf you would like to help us fix a bug or add a new feature, please check our\n[guidelines](CONTRIBUTING.md). Pull requests are welcome!\n\n\u003c!-- Thanks go to our wonderful contributors: --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003e\u003ca href=\"https://fosstodon.org/@ehmicky\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/8136211?v=4?s=100\" width=\"100px;\" alt=\"ehmicky\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eehmicky\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/ehmicky/error-serializer/commits?author=ehmicky\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#design-ehmicky\" title=\"Design\"\u003e🎨\u003c/a\u003e \u003ca href=\"#ideas-ehmicky\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"https://github.com/ehmicky/error-serializer/commits?author=ehmicky\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/papb\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/20914054?v=4?s=100\" width=\"100px;\" alt=\"Pedro Augusto de Paula Barbosa\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ePedro Augusto de Paula Barbosa\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/ehmicky/error-serializer/issues?q=author%3Apapb\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/ehmicky/error-serializer/commits?author=papb\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n  \u003ctfoot\u003e\n\n  \u003c/tfoot\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fehmicky%2Ferror-serializer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fehmicky%2Ferror-serializer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fehmicky%2Ferror-serializer/lists"}