Why is my custom Error object converted to a String by the Express router?

I am using custom Error objects in node.js (0.8.12) with express (2.5.8). When errors occur, I want to route them to my custom error handler, but my custom Error objects are converted to Strings, while native Error objects stay the same.


Here is a simple example:

var express = require('express');

var APIError = function(type) {
    this.type = type;
}
APIError.prototype = new Error();

var app = express.createServer();

app.use(app.router);
app.use(apiErrorHandler);

function log(source, err) {
  console.log(
    source, 
    typeof err, 
    err.constructor.name, 
    err instanceof APIError, 
    err instanceof Error
  );
}

function apiErrorHandler(err, req, res, next) {
  log("error handler:", err);
}

app.get('/', function(req, res, next) {
  var err = new APIError("notAllowed");
  log("router:", err);
  next(err);
});

app.listen(80);

The console output from this example is the following:

router: object Error true true
error handler: string String false false

If I replace new APIError("notAllowed") with new Error("notAllowed"), the object is conserved and a request produces this output:

router: object Error false true
error handler: object Error false true

Why is my custom Error object converted, although it is an instance of Error?

Try this. Note that APIError is now a named function:

var util = require('util');

function APIError(type) {
    Error.call(this, {
        message: type,
        constructorOpt: APIError
    });
    this.name = 'APIError';
}
util.inherits(APIError, Error);
APIError.prototype.name = 'APIError';

Also, have a look here.

In fact what's happening is that the string showing up is not your error object at all - it's another error being thrown inside the guts of Express (an "illegal access" exception). The error is happening when Express is comparing the error object to a string.

The root cause is apparently setting the "type" property on your custom Error object. This is apparently a no-no with V8 - it causes toString() to thrown the "illegal access" exception. More details here: https://code.google.com/p/v8/issues/detail?id=2397