Because the exception occurs inside the fs.open() async callback so that exception goes back into the async event handler in fs.open() that called the completion callback where it then disappears and has no chance to be propagated anywhere. Bluebird never has a chance to see it.

This is a textbook example of why you should not mix regular async callback code with promise code. Instead, promisify fs.open() and use the promisified version and then the exception will be caught appropriately by the promise infrastructure.

That will automatically create fs.openAsync() which returns a promise and promisified versions of all the other async methods.

FYI, the promise infrastructure can only catch exceptions in callbacks that are called by the promise infrastructure itself. It does that by wrapping the call to each callback in it's own try/catch. As you see in your code, you are using the fs.open() callback directly which has no such chance to get wrapped in such a try/catch handler to catch the exception and turn it into a rejection. So, instead, the usual solution is to create a promisified version of fs.open() that immediately rejects or resolves in the callback and then your custom callback code goes in the .then() handler where the callback is wrapped and exceptions will be caught and automatically turned into rejections.

Email codedump link for Why is an error thrown from within an async function inside a bluebird promise not caught in the .catch() function?