user994165
user994165

Reputation: 9502

JavaScript exception thrown is not of type "Error"

I'm using Restify and somewhere in the Restify library, an exception is being thrown due to some bad inputs on the user side. I have some simplified code below that recreates the issue. The problem in the example below is in an asynchronous function that tries to execute doesntexist.nofunction. What happens is that an exception is thrown then caught in the "server.on('uncaughtException.." function, but the "err" object is actually an "IncomingMessage" type, not an "Error" type. I have a few questions about this.

1) Should exceptions thrown always be of type "Error" and if not, is this a bug in Restify?

2) Is it a best practice for libraries that take in a callback parameter to also set an "err" parameter if there's an error, and let the client handle it in the callback as opposed to the library throwing an exception?

var restify = require('restify');

//Test with long stack traces and without it.
//var longStackTraces = require('long-stack-traces');

const server = restify.createServer({
    name: 'myapp',
    version: '1.0.0'
});

server.get('/', function (req, res, next) {
    try {
        setTimeout(function () {
            doesntexist.nofunction();
        }, 200);

        return next();
    } catch (err) {
        console.log("Caught error");
    }
});

server.on('uncaughtException', function (err) {
    console.log("uncaught exception1: " + err.constructor);
});

process.on('uncaughtException', function (err) {
    console.log("uncaught exception2: " + err.constructor);
});

server.listen(9123, function () {
    console.log('%s listening at %s', server.name, server.url);
});

Test:

curl http://localhost:9123

Console output without long stack traces:

myapp listening at http://[::]:9123
uncaught exception1: function IncomingMessage(socket) {
  Stream.Readable.call(this)
...
Error: uncaught exception1
    at Server.<anonymous> (/usr/apps/myapp/Temp.js:22:12)
    at emitMany (events.js:132:20)
    at Server.emit (events.js:201:7)
    at Domain.onError (/usr/apps/myapp/node_modules/restify/lib/server.js:968:18)
    at emitOne (events.js:96:13)
    at Domain.emit (events.js:188:7)
    at Domain._errorHandler (domain.js:97:23)
    at process._fatalException (bootstrap_node.js:293:33)

Console output without long stack traces:

Upvotes: 1

Views: 86

Answers (1)

000
000

Reputation: 27227

  1. Node-style callback functions should have a signature with err as the first argument. This is not in any spec, per se, but is a community norm.

Your code is like this:

server.get('/', function (req, res, next) {
    try {
        setTimeout(function () {
            doesntexist.nofunction();
        }, 200);

        return next();
    } catch (err) {
        console.log("Caught error");
    }
});

I would rewrite it like this:

server.get('/', function (req, res, next) {
    setTimeout(function () {
        try {
            doesntexist.nofunction();
            next();
        } catch (err) {
            next(err);
        }
    }, 200);
});

next is a node-style callback with err as the first argument, as is tradition. Make use of it by providing the err argument when needed.

Upvotes: 1

Related Questions