Edit Page

Errors

When a call to any model method or helper fails, Sails throws a JavaScript Error instance whose properties can be useful in diagnosing what went wrong.

Waterline normalizes these Error instances, classifying them with consistent err.name values and, when applicable, err.code:

try {
  await Something.create({…});
} catch (err) {
  // err.name
  // err.code
  // …
}

Negotiating errors

#

Catch-all error handling, while better than nothing, often just isn't enough. (There's a big difference between "that is not a valid username" and "we aren't able to create new users at all right now".) In order to negotiate the different kinds of errors appropriately, you'll need to be able to examine them in a granular way.

Fortunately, Sails provides some syntactic sugar for doing this out of the box, without resorting to try… catch: .intercept() and .tolerate().

await Something.create({…})
.intercept((err)=>{
 // Return a modified error here (or a special exit signal)
 // and .create() will throw that instead
 err.message = 'Uh oh: '+err.message;
 return err;
});
Property Type Details
name String The broad classification of the error.

e.g.'UsageError'
message String See .message.
stack String See .stack.
code String? A narrower classification of the error that is sometimes included.

e.g. 'E_UNIQUE'

When using code that interacts with Waterline (usually through model methods) there are a few different kinds of error you may encounter.

Usage errors

#

When an error has name: 'UsageError', this indicates that a Waterline method was used incorrectly, or executed with invalid options (for example, attempting to create a new record that would violate one of your model's high-level validation rules.)

This sort of error can come from any model method.

err.name === 'UsageError'

Adapter errors

#

Adapter errors usually indicate a problem in the underlying adapter, and not in the request itself. This can happen when a database goes offline, when there is a permission issue, because of some database-specific edge case, or (more rarely) a bug in the adapter. This kind of error will have name: 'AdapterError'.

This sort of error can come from any model method.

err.name === 'AdapterError'
E_UNIQUE
#

A uniqueness error occurs when a value that should be unique matches that of another record in the database. While this is considered an adapter error, it has its own code to differentiate it from a normal adapter error: code: 'E_UNIQUE'.

This sort of error can only come from the .create(), .update(), .addToCollection(), and .replaceCollection() model methods.

err.code === 'E_UNIQUE'

Examples

#

The exact strategy you use to do this in your Sails app depends on whether you're using await, promises, or callbacks.

Negotiating errors with await
#

To handle the different errors that may occur when attempting to create a new user from within an action:

await User.create({ emailAddress: inputs.emailAddress })
// Uniqueness constraint violation
.intercept('E_UNIQUE', (err)=> {
  return 'emailAlreadyInUse';
})
// Some other kind of usage / validation error
.intercept({name:'UsageError'}, (err)=> {
  return 'invalid';
});
// If something completely unexpected happened, the error will be thrown as-is.

return exits.success();
Negotiating errors with callbacks or promise chaining
#

If you're not able to use await because you're using Node.js <= v7.9, then prepare yourself: error handling works a bit differently when using callbacks or promise chaining instead of await.

Please use await if at all possible! It is much safer for your app, your code will be cleaner, and you will be happier.

For example, if you're using promise chaining, here's how you might handle the different errors that could occur when attempting to create a new user:

User.create({
  emailAddress: req.param('emailAddress')
})
.then(function (){
  res.ok();
})
// Uniqueness constraint violation
.catch({ code: 'E_UNIQUE' }, function (err) {
  res.sendStatus(409);
})
// Some other kind of usage / validation error
.catch({ name: 'UsageError' }, function (err) {
  res.badRequest();
})
// If something completely unexpected happened.
.catch(function (err) {
  res.serverError(err);
});

Here's the same example, but written with traditional Node.js callbacks instead of promise chaining:

User.create({
  emailAddress: req.param('emailAddress')
})
.exec(function (err){
  if (err && err.code === 'E_UNIQUE') {
    return res.sendStatus(409);
  } else if (err && err.name === 'UsageError') {
    return res.badRequest();
  } else if (err) {
    return res.serverError(err);
  }

  return res.ok();
});

But beware uncaught exceptions!

Is something missing?

If you notice something we've missed or could be improved on, please follow this link and submit a pull request to the sails repo. Once we merge it, the changes will be reflected on the website the next time it is deployed.

Concepts