If i understand you right, you're asking about how to propagate the error to the client with enough information.
first of all, javascript is dynamic, so you could just add the properties you need to your Error instance before passing it to the callback/response.
if (can === false && mod._id !== userid) {
var error = new Error("unauthorized")
error.code = 401
error.id = "not_authorized"
return callback(error);
}
Don't forget that in the matter of separation of concerns, every layer has it's own semantics and it has to encapsulate the lower layers. This is also true for error handling. Sometimes it is suitable to let the error just bubble up, but in most of the time this is bad, or at least bad user experience. So at least in the Controller you should transform any error bubbling up here to user/client-friendly http error codes. For this you have to think about what does an error mean to the upper next layer.
so the code like res.send(404, err.message)
is easy, but not very helpful. If you really want to do a good error handling then you have to do a step further and do some matching here. In static typed languages like Java you can do matching on Type. For JS this is possible too (with instanceof), but this is not very reliable. But you could use every other property or introduce own property with well defined error types.
var error = new Error("Some lengthy message for humans, who are reading log files")
error.errType = require('./errorTypes').NOT_AUTORIZED
callback(error)
and in the api user code
if(err){
if(err.errType === errorTypes.NOT_AUTHORIZED)
return res.send(401, "Wrong credentials")
}
you could, to reduce code duplicates, extract the error matching into an own module or a simple function, which maps internal types to external.
so this is simple (not the same as easy, easy depends on your context), and it is clean in the sense of callback style code. same is valid for promise based apis, only there you have error propagation and separation of resolve and reject control flows.
What i do not cover are things like Node.js domains (since they are not easy to use with express) and Zone.js stuff. This things might bring another tool-chains for error handling, but in the essence it's still the same. You have to transform errors somewhere.