{"id":19478853,"url":"https://github.com/xan105/node-error","last_synced_at":"2026-04-25T22:32:07.477Z","repository":{"id":44028621,"uuid":"440330547","full_name":"xan105/node-error","owner":"xan105","description":"Error handling tools","archived":false,"fork":false,"pushed_at":"2024-04-09T03:45:25.000Z","size":784,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-20T02:53:09.130Z","etag":null,"topics":["attempt","error","errorcode","errorlookup","fail","failure","match","nodejs"],"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/xan105.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"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},"funding":{"github":"xan105","custom":"https://www.paypal.me/xan105","patreon":"xan105"}},"created_at":"2021-12-20T23:09:59.000Z","updated_at":"2024-03-01T00:50:20.000Z","dependencies_parsed_at":"2023-01-30T17:55:12.688Z","dependency_job_id":"a916b7bc-5a33-4225-866d-2abbe85bc4d1","html_url":"https://github.com/xan105/node-error","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/xan105/node-error","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xan105%2Fnode-error","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xan105%2Fnode-error/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xan105%2Fnode-error/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xan105%2Fnode-error/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xan105","download_url":"https://codeload.github.com/xan105/node-error/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xan105%2Fnode-error/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32279652,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T18:29:39.964Z","status":"ssl_error","status_checked_at":"2026-04-25T18:29:32.149Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["attempt","error","errorcode","errorlookup","fail","failure","match","nodejs"],"created_at":"2024-11-10T19:51:44.887Z","updated_at":"2026-04-25T22:32:07.471Z","avatar_url":"https://github.com/xan105.png","language":"JavaScript","funding_links":["https://github.com/sponsors/xan105","https://www.paypal.me/xan105","https://patreon.com/xan105"],"categories":[],"sub_categories":[],"readme":"About\n=====\n\nError handling tools:\n\n- Custom Error type `Failure` extending the `Error` constructor\n- Linux/Windows standard error codes and their description\n- Error lookup: retrieve description associated to status code (or other code)\n- GoLang style error handling: return value instead of throwing\n- Rust style error handling: `match Result\u003cT, E\u003e` pattern\n\n📦 Scoped `@xan105` packages are for my own personal use but feel free to use them.\n\nExample\n=======\n\n```js\nimport { Failure } from \"@xan105/error\";\n\nif (something)\n  throw new Failure(\"my super error message\", \"ERR_CODE\");\n```\n\nOutput:\n\n```\nFailure [ERR_CODE]: my super error message\n    StackTrace...\n    .............\n    ............. {\n  code: 'ERR_CODE'\n}\n```\n\n- GoLang style error\n\n```js\nimport { attempt } from \"@xan105/error\";\nimport { readFile } from \"node:fs/promises\";\n\nconst [ file, err ] = await attempt(readFile, [filePath]);\nif(err) console.error(err); //handle error\n//ignore error and set a default value\nconst [ json = {} ] = attempt(JSON.parse, [file]);\n//skip value\nconst [, err] = attempt(foo, [\"bar\"]);\n\n//if you prefer a node:util/promisify like syntax\nimport { attemptify } from \"@xan105/error\";\nconst [json] = attemptify(JSON.parse)(file);\n```\n\n- Rust style error (`match Result\u003cT, E\u003e` pattern)\n\n```js\nimport { match } from \"@xan105/error\";\nimport { readFile } from \"node:fs/promises\";\n\nconst file = await match(readFile, [filePath], {\n  Err: (err) =\u003e { console.error(err); } //handle error\n});\n```\n\n- Windows error lookup with shell32 API (FFI)\n\n```js\nimport { Failure, errorLookup } from \"@xan105/error\";\n\n// ... Some FFI implementation code\n\nconst hr = SHQueryUserNotificationState(pquns);\nif (hr \u003c 0) throw new Failure(...errorLookup(hr));\n```\n\nLet's say this would fail with error `0x8000FFFF`\n\nOutput:\n```\nFailure [E_UNEXPECTED]: Catastrophic failure\nStackTrace...\n    .............\n    ............. {\n  code: 'E_UNEXPECTED'\n}\n```\n\nInstall\n=======\n\n```\nnpm install @xan105/error\n```\n\nAPI\n===\n\n⚠️ This module is only available as an ECMAScript module (ESM).\u003cbr /\u003e\n\n## Named export\n\n### `Failure(message: string | object, option?: string | number | object): class`\n\nCreate an error with optional information.\u003cbr /\u003e\nThis extends the regular `Error` constructor.\n\n|option|default|description|\n|------|-------|-----------|\n|code|none|optional custom error code (see below for details)|\n|cause|none|additional details about the error or the parent error|\n|clean|true|remove unhelpful internal stack trace entries|\n|filter|none|additional string[] of path(s) to filter when using clean| \n\n`code` (if any) is expected to be a string if it's an integer then the following will be used instead:\n\n 0. ERR_UNEXPECTED\n 1. ERR_INVALID_ARG\n 2. ERR_ASSERTION\n 3. ERR_UNSUPPORTED\n  \nif `option` is either a string or a number then it specifies the error code.\n \nOutput Example:\n\n`new Failure(\"Expecting a string !\",\"ERR_INVALID_ARG\");`\n\n```\nFailure [ERR_INVALID_ARG]: Expecting a string !\n    at file:///D:/Documents/GitHub/xan105/node-error/test/test.js:3:12\n    at ModuleJob.run (node:internal/modules/esm/module_job:185:25)\n    at async Promise.all (index 0)\n    at async ESMLoader.import (node:internal/modules/esm/loader:281:24)\n    at async loadESM (node:internal/process/esm_loader:88:5)\n    at async handleMainPromise (node:internal/modules/run_main:65:12) {\n  code: 'ERR_INVALID_ARG'\n}\n```\n\n`new Failure(\"Expecting a string !\", { code: 1, cause: { foo: \"bar\" } });`\n\n```\nFailure [ERR_INVALID_ARG]: Expecting a string !\n    at file:///D:/Documents/GitHub/xan105/node-error/test/test.js:3:12\n    at ModuleJob.run (node:internal/modules/esm/module_job:185:25)\n    at async Promise.all (index 0)\n    at async ESMLoader.import (node:internal/modules/esm/loader:281:24)\n    at async loadESM (node:internal/process/esm_loader:88:5)\n    at async handleMainPromise (node:internal/modules/run_main:65:12) {\n  code: 'ERR_INVALID_ARG',\n  cause: { foo: 'bar' }\n}\n```\n\n`new Failure(\"Expecting a string !\", { clean: true });`\n\n```\nFailure: Expecting a string !\n    at file:///D:/Documents/GitHub/xan105/node-error/test/test.js:3:12\n    at async Promise.all (index 0)\n```\n\n### `codes: object`\n\nA list of standard error codes with their description.\u003cbr /\u003e\nErrors are listed by their unsigned numerical value as `value:number = [description: string, code: string]`\n\n```js\n{\n  1: [\"Operation not permitted\", \"EPERM\"],\n  2: [\"No such file or directory\", \"ENOENT\"],\n  3: [\"No such process\", \"ESRCH\"],\n  ...\n}\n```\n\n#### Available error code range are:\n\n - `linux`\n   \n    Linux error codes 1 to 131.\n   \n - `windows` \n \n    Windows error codes 1 to 15841.\n   \n - `hresult` \n \n    HRESULT codes are most commonly encountered in COM programming. Includes common and WMI error codes.\n \n - `ntstatus` \n \n    NTSTATUS values are mostly used like HRESULT but they have different codes.\n    \n - `win32` \n \n    Windows and hresult error codes merged together since their error code range don't overlap.\u003cbr /\u003e\n    This is also for backward compatibility with previous version of `errorLookup()`\n\n#### They are also available under their own namespace:\n\n```js\nimport { codes } from \"@xan105/error\"\nconsole.log(codes.windows);\n\nimport { windows } from \"@xan105/error/codes\"\nconsole.log(windows);\n```\n\n#### Usage example:\n\n\u003cdetails\u003e\n\u003csummary\u003eLinux\u003c/summary\u003e\n\n```js\nimport { Failure, codes } from \"@xan105/error\"\nthrow new Failure(...codes.linux[2]);\n/*\nFailure [ENOENT]: No such file or directory\n    StackTrace...\n    .............\n    ............. {\n  code: 'ENOENT'\n}\n*/\n```\n\n```js\nimport { Failure, codes } from \"@xan105/error\"\nconst [description, code] = codes.linux[1];\nthrow new Failure(description, { code, cause: { foo: \"bar\" } });\n/*\nFailure [EPERM]: Operation not permitted,\n    StackTrace...\n    .............\n    ............. {\n  code: 'EPERM',\n  cause: { foo: 'bar' }\n}\n*/\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWindows\u003c/summary\u003e\n\n```js\nimport { Failure, codes } from \"@xan105/error\"\nthrow new Failure(...codes.windows[2]);\n/*\nFailure [ERROR_FILE_NOT_FOUND]: The system cannot find the file specified\n    StackTrace...\n    .............\n    ............. {\n  code: 'ERROR_FILE_NOT_FOUND'\n}\n*/\n```\n\n```js\nimport { Failure, codes } from \"@xan105/error\"\nconst [description, code] = codes.windows[1];\nthrow new Failure(description, { code, cause: { foo: \"bar\" } });\n/*\nFailure [ERROR_INVALID_FUNCTION]: Incorrect function\n    StackTrace...\n    .............\n    ............. {\n  code: 'ERROR_INVALID_FUNCTION',\n  cause: { foo: 'bar' }\n}\n*/\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWindows HRESULT\u003c/summary\u003e\n\nExample with error `2147749921 (0x80041021)`:\n\n```js\nimport { Failure, codes } from \"@xan105/error\"\n\nconst hr = someWin32API(); //received error -2147217375\nconst code = new Uint32Array([hr])[0]; //cast signed to unsigned\nthrow new Failure(...codes.hresult[code]);\n/*\nFailure [WBEM_E_INVALID_SYNTAX]: Query is syntactically not valid\n    StackTrace...\n    .............\n    ............. {\n  code: 'WBEM_E_INVALID_SYNTAX'\n}\n*/\n```\n\n\u003c/details\u003e\n\n### `errorLookup(code: number | string, range?: string): string[]`\n\nRetrieve information about an error by its numerical status code (or other code).\n\nReturn an array of string as `[message: string, code?: string]`.\n\nYou can use it directly with `Failure`:\n\n```js\nnew Failure(...errorLookup(0x80041021));\nnew Failure(...errorLookup(2147749921));\nnew Failure(...errorLookup(-2147217375));\nnew Failure(...errorLookup(\"WBEM_E_INVALID_SYNTAX\"));\n\n/*\nFailure [WBEM_E_INVALID_SYNTAX]: Query is syntactically not valid\n    StackTrace...\n    .............\n    ............. {\n  code: 'WBEM_E_INVALID_SYNTAX'\n}\n*/\n```\n\nSee `codes` above for available error code range.\nIf omitted `linux` is used under Linux and `win32` under Windows.\n\n### `attempt(fn: unknown, args?: unknown[]):Promise\u003cunknown[]\u003e | unknown[]`\n\nThis is a try/catch wrapper to change how an error is handled.\u003cbr /\u003e\nInstead of throwing returns an error as a value similar to GoLang.\n\nBy leveraging the destructure syntax we can easily provide a default value in case of error and/or choose to completely ignore to handle any error.\u003cbr /\u003e\nAnd if we want to handle any error we can do so like we would with any value.\n\nExample\n\n```js\nimport { readFile } from \"node:fs/promises\";\n  \n//read the file\nconst [ file, err ] = await attempt(readFile, [filePath]);\nif(err) //in case of error do something;\n\n//ignore error and set a default value\nconst [ json = {} ] = attempt(JSON.parse, [file]);\n\n//skip value\nconst [, err] = attempt(foo, [\"bar\"]);\n```\n\nThis doesn't replace try/catch it's an alternative.\u003cbr /\u003e\nIt is particularly useful to avoid these patterns:\n\n- Using `let` instead of `const` because the variable needs to be outside of the try/catch scope.\n\n```js\n\n//Instead of\nlet json;\ntry{\n  json = JSON.parse(string);\n} catch { /*do nothing*/ }\nreturn json; //do something\n\n//You could do\nconst [ json ] = attempt(JSON.parse,[string]);\nreturn json; //do something\n```\n\n- Nested try/catch which are sometimes unavoidable and impact readability.\n\n```js\n//Instead of\ntry{\n  foo();\n}catch(err){\n  try{\n    bar();\n  }catch(err){\n    if (err.code === \"ENOENT\")\n      throw new Error(\"It didn't work\");\n  }\n}\n\n//You could do\nif (attempt(foo)[1] \u0026\u0026 attempt(bar)[1]?.code === \"ENOENT\"){\n  throw new Error(\"It didn't work\");    \n}\n```\n\n**Parameters:**\n  \n  - fn: The value to resolve\n  \n  If `fn` is a promise then this function will behave like one.\n  eg:\n```js\n//Promise\nconst [ file ] = await attempt(fs.Promises.readFile, [filePath]);\n//Sync\nconst [ json ] = attempt(JSON.parse, [file]);\n```\n\n  You can also use anonymous function (or wrap in one).\n  eg:\n```js\nconst [result] = attempt( ()=\u003e \"value\" );\nconst [result] = attempt( (x)=\u003e x, [\"value\"] );\nconst [json] = attempt(()=\u003e JSON.parse(string) );\nconst [json] = attempt(()=\u003e JSON.stringify(JSON.parse(string)) );\n```\n  \n  - args: Optional list of arguments to pass to fn\n\n**Return value:**\n  \n  Returns the result and the error together as an array as `[result, error]`.\u003cbr /\u003e\n  If there is an error result will be _undefined_.\u003cbr /\u003e\n  Otherwise error will be _undefined_.\n  \n  💡 _undefined_ is used to represent the lack/nonexistence of value because destructuring default value assignment triggers only with _undefined_.\n\nUsage example with node:util/promisify:\n\n```js\nimport { promisify } from \"node:util\";\nimport { execFile } from \"node:child_process\";\nimport { attempt, Failure } from \"@xan105/error\";\n\nconst [ ps, err ] = await attempt(promisify(execFile), [\"pwsh\", [\n  \"-NoProfile\", \n  \"-NoLogo\", \n  \"-Command\", \n  \"$PSVersionTable.PSVersion.ToString()\"\n], { windowsHide: true }]);\n\nif (err || ps.stderr) throw new Failure(err?.stderr || ps.stderr, \"ERR_POWERSHELL\");\nconsole.log(ps.stdout);\n```\n\n#### Special case\n\n##### Loosing \"this\" context\n\n⚠️ NB: If you get an error like:\n```\nTypeError: x called on non-object\nTypeError: Illegal invocation\n```\n\nThis is most likely because what you are invoking lost its `this` context.\nYou need to `bind` it to its constructor or use an arrow function.\n\n`Promise` static methods such as `.all()`, `.any()`, `.allSettled()` , etc is a good example of this:\n\n```js\nconst promise1 = new Promise((resolve) =\u003e setTimeout(resolve, 100, 'quick'));\nconst promise2 = new Promise((resolve) =\u003e setTimeout(resolve, 500, 'slow'));\nconst promises = [promise1, promise2];\n\n//This will succeed\nconst [ result, error ] = await attempt(()=\u003e Promise.any(promises));\n\n//This will fail with a TypeError\nconst [ result, error ] = await attempt(Promise.any, [promises]);\n/*\n[\n  undefined,\n  TypeError: Promise.any called on non-object\n      at any (\u003canonymous\u003e)\n      StackTrace...\n]\n*/\n\n//This will succeed\nconst [ result, error ] = await attempt(Promise.any.bind(Promise), [promises]);\n```\n\n##### Computed properties (Getter/Setter)\n\nThe actual function behind the Getter/Setter will be called when that property is looked up.\nTherefore if there was any error it would throw before `attempt()` could catch it.\n\n```js\nclass Foo {\n  constructor(){}\n  \n  get bar(){\n    throw new Error(\"error\");\n  }\n}\n\nconst foo = new Foo();\nconst [, err] = attempt(foo.bar); \n```\n\nTo catch it you need to pass the actual function behind the Getter/Setter.\n\n```js\nclass Foo {\n  constructor(){}\n  \n  get bar(){\n    throw new Error(\"error\");\n  }\n}\n\nconst foo = new Foo();\nconst descriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(foo), \"bar\");\nconst [, err] = attempt(descriptor?.[\"get\"]);\n```\n\n### `attemptify(fn: unknown): (...args: unknown[]) =\u003e Promise\u003cunknown[]\u003e | unknown[]`\n\nnode:util/promisify style syntax for `attempt()`:\n\n```js\nfunction double(i){\n  return i * 2;\n}\n\n//Instead of\nconst j = attempt(double, [2]);\n\n//You can use\nconst j = attemptify(double)(2);\n```\n\nThis is a simple wrapper to `attempt()`.\n\n### `match(fn: unknown, args: unknown[], cb?: { Ok?: function, Err?: function }):Promise\u003cunknown\u003e | unknown`\n\nThis is a try/catch wrapper to change how an error is handled.\u003cbr /\u003e\nSimilar to the Rust `match Result\u003cT, E\u003e` pattern:\n\nSuccess is handled by the `Ok()` function and failure by the `Err()` function respectively.\n\n```js\nconst greetings = (name) =\u003e `hello ${name}`;\n\nconst message = match(greetings, [\"Xan\"], {\n  Ok: (value) =\u003e value,\n  Err: (err) =\u003e { console.log(err) }\n});\n```\n\nThe `Ok()` function is expected to return the value the `match()` function shall return for value assignment.\u003cbr /\u003e\n💡 `Ok()` and `Err()` can both be omitted.\n\n```js\nconst greetings = (name) =\u003e `hello ${name}`;\n\nconst message = match(greetings, [\"Xan\"], {\n  Err: (err) =\u003e { console.log(err) }\n});\n```\n\nIf `fn` is a promise then this function will behave like one:\n\n```js\n//Promise\nconst file = await match(fs.Promises.readFile, [filePath]);\n//Sync\nconst json = match(JSON.parse, [file]);\n```\n\nIn case of error, If `Err()` returns a value it will be used for value assignment.\u003cbr /\u003e\nUse this to ignore an error and set a default value:\n\n```js\nconst json = match(JSON.parse, [file], {\n  Err: ()=\u003e { return {} }\n});\n```\n\n#### Special case\n\n⚠️ This function is similar to the above export `attempt()` and therefore inherits the same remarks (_see above_).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxan105%2Fnode-error","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxan105%2Fnode-error","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxan105%2Fnode-error/lists"}