Code Monkey home page Code Monkey logo

error's Introduction

error

Wrap errors with more context.

Inspiration

This module is inspired by the go error libraries that have simple functions for creating & wrapping errors.

This is based on libraries like eris & pkg/errors

Older version of error

If you are looking for the older v7 version of error you should check v7.x branch

Using error with async / await

Check out resultify !

The rest of the examples use plain vanilla callbacks.

Motivation

Wrapping errors when bubbling up instead of just doing if (err) return cb(err) allows you to pass more context up the stack.

Common example include passing along parameters from the DB read related to the failure or passing along any context from the user in a HTTP request when doing a failure.

This can give you nice to read messages that include more information about the failure as it bubbles up.

There is more information about how to handle errors in this article Don't just check errors, handle them gracefully

If you want a deep dive into the difference between Programming and Operational errors please check out this guide

examples:

const { wrapf } = require('error')

function authenticatRequest(req) {
  authenticate(req.user, (err) => {
    if (err) {
      return cb(wrapf('authenticate failed', err))
    }
    cb(null)
  })
}

or

const { wrapf } = require('error')

function readFile(path, cb) {
  fs.open(path, 'r', (err, fd) => {
    if (err) {
      return cb(wrapf('open failed', err, { path }))
    }

    const buf = Buffer.alloc(64 * 1024)
    fs.read(fd, buf, 0, buf.length, 0, (err) => {
      if (err) {
        return cb(wrapf('read failed', err, { path }))
      }

      fs.close(fd, (err) => {
        if (err) {
          return cb(wrapf('close failed', err, { path }))
        }

        cb(null, buf)
      })
    })
  })
}

Structured errors

const { SError } = require('error')

class ServerError extends SError {}
class ClientError extends SError {}

const err = ServerError.create(
  '{title} server error, status={statusCode}', {
    title: 'some title',
    statusCode: 500
  }
)
const err2 = ClientError.create(
  '{title} client error, status={statusCode}', {
    title: 'some title',
    statusCode: 404
  }
)

Wrapped Errors

const net = require('net');
const { WError } = require('error')

class ServerListenError extends WError {}

var server = net.createServer();

server.on('error', function onError(err) {
  if (err.code === 'EADDRINUSE') {
    throw ServerListenFailedError.wrap(
      'error in server, on port={requestPort}', err, {
        requestPort: 3000,
        host: null
      }
    )
  } else {
    throw err;
  }
});

server.listen(3000);

Comparison to Alternatives.

There are alternative existing libraries for creating typed and wrapped errors on npm. Here's a quick comparison to some alternatives.

This module takes inspiration from verror and adds improvements.

  • You can pass extra fields as meta data on the error
  • The templating forces dynamic strings to be extra fields.
  • Uses ES6 classes for inheritance. This gives your errors unique class names and makes them show up in heapdumps.
  • Has JSON.stringify support

This package used to have a completely different API on the 7.x branch.

  • New error module uses actual classes instead of dynamically monkey patching fields onto new Error()
  • Implementation is more static, previous code was very dynamic
  • Simpler API, see the message & properties in one place.
  • wrapf & errorf helpers for less boilerplate.

Hand writing Error sub classes.

You can create your own Error classes by hand. This tends to lead to 10-20 lines of boilerplate per error which is replace with one line by using the error module; aka

class AccountsServerFailureError extends SError {}
class ConnectionResetError extends WError {}

The ono package has similar functionality with a different API

  • ono encourages plain errors instead of custom errors by default
  • error has zero dependencies
  • error is only one simple file. ono is 10.
  • error implementation is more static, ono is very dynamic.

Documentation

This package implements three classes, WError; SError & MultiError

You are expected to subclass either WError or SError;

  • SError stands for Structured Error; it's an error base class for adding informational fields to your error beyond just having a message.
  • WError stands for Wrapped Error; it's an error base class for when you are wrapping an existing error with more information.

The MultiError class exists to store an array of errors but still return a single Error; This is useful if your doing a parallel operation and you want to wait for them all to finish and do something with all of the failures.

Some utility functions are also exported:

  • findCauseByName; See if error or any of it's causes is of the type name.
  • fullStack; Take a wrapped error and compute a full stack.
  • wrapf; Utility function to quickly wrap
  • errorf; Utility function to quickly create an error
  • getInfo; Utility function to get the info for any error object. Calls err.info() if the method exists.

WError

Example:

class ServerListenError extends WError {}

ServerListenError.wrap('error in server', err, {
  port: 3000
})

When using the WError class it's recommended to always call the static wrap() method instead of calling the constructor directly.

Example (without cause message):

class ApplicationStartupError extends WError {}

ApplicationStartupError.wrap(
  'Could not start the application cleanly: {reason}',
  err,
  {
    skipCauseMessage: true,
    reason: 'Failed to read from disk'
  }
)

Setting skipCauseMessage: true will not append the cause error message but still make the cause object available.

const werr = new WError(message, cause, info)

Internal constructor, should pass a message string, a cause error and a info object (or null).

WError.wrap(msgTmpl, cause, info)

wrap() method to create error instances. This applies the string-template templating to msgTmpl with info as a parameter.

The cause parameter must be an error The info parameter is an object or null.

The info parameter can contain the field skipCauseMessage: true which will make WError not append : ${causeMessage} to the message of the error.

werr.type

The type field is the machine readable type for this error. Always use err.type and never err.message when trying to determine what kind of error it is.

The type field is unlikely to change but the message field can change.

werr.fullType()

Calling fullType will compute a full type for this error and any causes that it wraps. This gives you a long type string that's a concat for every wrapped cause.

werr.cause()

Returns the cause error.

werr.info()

Returns the info object passed on. This is merged with the info of all cause errors up the chain.

werr.toJSON()

The WError class implements toJSON() so that the JSON serialization makes sense.

WError.fullStack(err)

This returns a full stack; which is a concatenation of this stack trace and the stack trace of all causes in the cause chain

WError.findCauseByName(err, name)

Given an err and a name will find if the err or any causes implement the type of that name.

This allows you to check if a wrapped ApplicationError has for example a LevelReadError or LevelWriteError in it's cause chain and handle database errors differently from all other app errors.

SError

Example:

class LevelReadError extends SError {}

LevelReadError.create('Could not read key: {key}', {
  key: '/some/key'
})

When using the SError class it's recommended to always call the static create() method instead of calling the constructor directly.

const serr = new SError(message, info)

Internal constructor that takes a message string & an info object.

SError.create(messageTmpl, info)

The main way to create error objects, takes a message template and an info object.

It will use string-template to apply the template with the info object as a parameter.

SError.getInfo(error)

Static method to getInfo on a maybe error. The error can be null or undefined, it can be a plain new Error() or it can be a structured or wrapped error.

Will return err.info() if it exists, returns {} if its null and returns { ...err } if its a plain vanilla error.

serr.type

Returns the type field. The err.type field is machine readable. Always use err.type & not err.message when trying to compare errors or do any introspection.

The type field is unlikely to change but the message field can change.

serr.info()

Returns the info object for this error.

serr.toJSON()

This class can JSON serialize cleanly.

MultiError

Example:

class FanoutError extends MultiError {}

function doStuff (filePath, cb) {
  fanoutDiskReads(filePath, (errors, fileContents) => {
    if (errors && errors.length > 0) {
      const err = FanoutError.errorFromList(errors)
      return cb(err)
    }

    // do stuff with files.
  })
}

When using the MultiError class it's recommended to always call the static errorFromList method instead of calling the constructor directly.

Usage from typescript

The error library does not have an index.d.ts but does have full jsdoc annotations so it should be typesafe to use.

You will need to configure your tsconfig appropiately ...

{
  "compilerOptions": {
    ...
    "allowJs": true,
    ...
  },
  "include": [
    "src/**/*.js",
    "node_modules/error/index.js"
  ],
  "exclude": [
    "node_modules"
  ]
}

Typescript does not understand well type source code in node_modules without an index.d.ts by default, so you need to tell it to include the implementation of error/index.js during type checking and to allowJs to enable typechecking js + jsdoc comments.

Installation

npm install error

Contributors

  • Raynos

MIT Licenced

error's People

Contributors

andrewdeandrade avatar claypigeon123 avatar donatj avatar jcorbin avatar jessety avatar kriskowal avatar micburks avatar raynos avatar shesek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

error's Issues

TypeError: "name" is read-only

Hi,

I get the following error TypeError: "name" is read-only related to line 25 extend(createError, args); in file typed.js
.

Can you help me ?

Don't require `assert` module

Hey Jake and thanks for this module.

I'd really like to use this module for some simple error throwing in different low-level modules, but since this module depends on "assert" and "util" sadly that's not really an option.

By requiring assert and util (I'm only bothered by assert, because I use the "typed" errors), browserify will bundle all its builtins and this is a total bummer for small modules.

Maybe we could just throw instead of asserting? I know the code would be a bit more messy, but in return it'd make it much more light-weight.

I could make a PR if you're interested?

extend throws when run under strict mode

First off let me say thanks for all your open-source work! It is because of people like you I've learned some incredible things.

I also want to say I'm not sure what to do about this, or where the fix should lie so feel free to point the finger elsewhere ๐Ÿ˜„

This issue is related to this issue in cycle.js. cycle.js runs in strict mode. This recent commit ends up assigning the name property of source to the target function object createError which is usually a no-op but throws under strict mode with at least chrome.

Uncaught TypeError: Cannot assign to read only property 'name' of function createError(opts) {
            var result = new Error()... <more>

Add warning for 'illegal access' in node < 0.12

Using typed error and trying to log the error (or anything which causes toString to be called) results in a fatal 'illegal access' error in 0.10.x

willy@localhost:~/sync (willFetch)$ nave use 0.10
already using 0.10.38
willy@localhost:~/sync (willFetch)$ node
> var TypedError = require('error/typed')
undefined
> var Test = TypedError({type:'foo'})
undefined
> var e = Test()
undefined
> e

util.js:329
  return '[' + Error.prototype.toString.call(value) + ']';
                                        ^
illegal access

willy@localhost:~/sync/ (willFetch)$ nave use 0.12
Already installed: 0.12.4
using 0.12.4
willy@localhost:~/sync/ (willFetch)$ node
>  var TypedError = require('error/typed')
undefined
> var Test = TypedError({type:'foo'})
undefined
>  var e = Test()
undefined
> e
{ [FooError] type: 'foo', name: 'FooError', fullType: 'foo' }

Obviously this isn't something which can be fixed, but it's a hard to debug problem, so a warning in the readme would help here.

use captureStackTrace for v8

v8 engine support Error.captureStackTrace to shift stacktrace to real place where error created.

Do you accept a PR to add this feature for only node.js/io.js?

checking err is SomeTypedError?

What is the right way to check an err is a ServerError?

var TypedError = require("error/typed")

var ServerError = TypedError({
    type: 'server.5xx',
    message: '{title} server error, status={statusCode}',
    title: null,
    statusCode: null
});

var error = new ServerError({
    title:'some title',
    statusCode: 500
});

error instanceof ServerError // false

or by using err.name, err.type or err.fullType? (what are all these properties for?)

Thanks!

Request: Default template string

It would be nice to call an error like so:

class CustomError extends SError {
  static defaultTemplate =  'there was a problem with foo: {foo}'
}

error = CustomError.create({foo: 'bar'})
// => error.message = 'there was a problem with foo: bar'

Having the message template defined with the error seems to separate responsibilities better: the error message knows how to display the error, and the call-site does not need to know that. Seems to me to better design in some cases, by moving more logic to the error object and away from the call-site.

[Request/Question] TypeScript definitions

Hi,

Could you provide typescript definitions for your package?
Unfortunately I didn't found community definitions (on DefinitelyTyped/DefinitelyTyped), and I'm not enough skilled to create one (I can try but it would take time :x).

Thanks,

Regards.

What Even Is `MIGRATION.md`?

So like a lot of projects are on 4.x... I'd like to use wrapped error, added somewhere after 5.?... and why not go to 7.x while I'm at it? Well there's no file to tell me why not, or what to do...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.