Node.js: log ignored errors - javascript

Is there any way in node.js to log all exceptions?
process.on('uncaughtException') is not enough for me, because I need to log all caught and uncaught exceptions, even if there was a catch somewhere in the code which just ignored/swallowed the error.
Do you guys think, it is possible in node.js?

One hacky way to do this is using debug context:
const vm = require('vm');
const Debug = vm.runInDebugContext('Debug'); // Obtain Debug object
Debug.setListener((type, _, e) => { // listen for all debug events
if (type == Debug.DebugEvent.Exception) {
console.log(e.exception().stack) // e is an event object
}
});
Debug.setBreakOnException(); // this is required for Exception event to fire
try {
throw new Error('bla');
} catch(e) {
// ha
}
Warning: don't leave this code in production, use for debugging only.
Obviously, it won't call asynchronous errors, because they are not actually thrown, they are just created to passed to a callback.
Another way is to replace possible error constructors:
const OldError = Error;
const MyError = function(message) {
const err = new OldError(message);
OldError.captureStackTrace(err, MyError); // remove top frame from stack trace
console.log(err.stack);
return err;
}
MyError.prototype = Error.prototype; // Fix instanceof
global.Error = MyError;
try {
throw new Error('bla');
} catch(e) {
}
new Error('blabla');
This way you can also handle asynchronous error, but won't see if something other than instance Error is thrown.
If you are interested only in promises and you are using native v8 promises, then you can try this:
const vm = require('vm');
const Debug = vm.runInDebugContext('Debug');
Debug.setListener((type, _, e) => {
if (type == Debug.DebugEvent.PromiseEvent) {
if (e.status() === -1) { // 0=pending, 1=resolved, -1=rejected
console.log(e.value().value().stack);
}
}
});
Promise.reject(new Error('test'))
.catch(() => {});
It will likely generate some duplicates, since it catches child promise rejection as well as original promise rejection.

You could attach a debugger like node-inspector and active the option in node-inspector. This does not log exceptions but pause execution which should be enough to find the quirks in the 3rd party module.
If you're using WebStorm you can log uncaught exceptions to the console or to a file. After starting the WebStorm debugger open the breakpoints dialog and activate the "Any exception" setting for "JavaScript Exception Breakpoints" and breakpoint actions according to

If you are swallowing the exceptions you cannot track them.
If you think that a module that you're using is ignoring the exceptions you are using a bad module or you are not using it correctly.
If you are using Express the correct approach will be to redirect all the exception and errors with next(err).
The exceptions will be passed to the error handler (note the four parameters in the function) and there you can log them:
router.get('/', function (req, res, next) {
// your logic
if(err) {
return next(err);
}
return next();
});
// Error handler
app.use(function(err, req, res, next) {
console.log(err.stack);
res.status(err.status || 500).json({
error: {
code: err.code,
message: err.message
}
});
next(err);
});

Related

How to catch all internal errors from external code in JavaScript?

I have the following call to an API (an npm module running in Node.js) in a JavaScript file in which I would like to catch all errors so can gracefully handle them. But if I e.g. pass a bad API-KEY or a city name that does not exist, there is an error in the internal code of the API which is not caught by the try/catch:
const weather = require('openweather-apis');
const getTemperature = (city, cbSuccess, cbFailure) => {
try {
weather.setLang('de');
weather.setCity(city);
weather.setUnits('metric');
weather.setAPPID('BADKEY');
weather.getTemperature((err, temperature) => {
if (err) {
console.log(err);
} else {
console.log(`The temperature in ${city} is ${temperature}° C.`);
}
});
} catch (error) {
console.log('there was an error');
}
}
getTemperature('Berlin');
Rather, an error is displayed and execution stops:
C:\edward\nwo\jsasync\node_modules\openweather-apis\index.js:162
return callback(err,jsonObj.main.temp);
^
TypeError: Cannot read property 'temp' of undefined
at C:\edward\nwo\jsasync\node_modules\openweather-apis\index.js:162:40
at IncomingMessage.<anonymous> (C:\edward\nwo\jsasync\node_modules\openweather-apis\index.js:250:18)
at IncomingMessage.emit (events.js:194:15)
at endReadableNT (_stream_readable.js:1125:12)
at process._tickCallback (internal/process/next_tick.js:63:19)
Is there a way in JavaScript to catch all errors as one does in e.g. Java and C#?
I believe that something like this might work:
async execute(weather, city, temperature) {
return await new Promise(function(resolve, reject) {
weather.getTemperature((err, temperature) => {
if (err) {
reject(err);
} else {
resolve(`The temperature in ${city} is ${temperature}° C.`);
}
});
};
}
const getTemperature = async (city, cbSuccess, cbFailure) => {
try {
weather.setLang('de');
weather.setCity(city);
weather.setUnits('metric');
weather.setAPPID('BADKEY');
const res = await execute(weather, city, temperature);
console.log(res);
} catch (error) {
console.log('there was an error');
}
}
You're out of luck if an exception throws in asynchronous code. This will stop execution of the script (as you're seeing above).
The module you are using should possibly handle the error in a better way and pass the error in the callback err parameter. Unless you fork the code or file a bug you're stuck with this.
The same effect can be demonstrated here:
async function testAsyncException() {
try {
setTimeout(() => {
throw new Error("Error in asynchronous code");
}, 100);
} catch (e) {
// This will never be caught...
console.error("testAsyncException: A bad error occurred:", e);
}
}
process.on('uncaughtException', (e) => {
console.log("uncaughtException:", e);
})
testAsyncException();
The try .. catch block around the setTimeout call will not handle the generated exception.
The only way you can "catch" this type of exception is using a process event like so:
process.on('uncaughtException', (e) => {
console.log("uncaughtException:", e);
})
This however should only be used to log and then exit. Trying to recover program state at this point is not a good idea, since the application is in an unknown state.
If you're using a process manager such as the very useful PM2, the script can be automatically restarted on errors.
Conversely if we try the following:
function testSyncException() {
try {
throw new Error("Error in synchronous code");
} catch (e) {
// This will be caught...
console.error("testSyncException: A bad error occurred:", e);
}
}
testSyncException();
We can see that the exception will be caught.
I strongly recommend this excellent article on error handling by the creators of Node.js (Joyent):
https://www.joyent.com/node-js/production/design/errors
It details the best strategies for handling both Operational errors and Programmer errors.
there is an error in the internal code of the API
return callback(err,jsonObj.main.temp);
^
TypeError: Cannot read property 'temp' of undefined
at C:\edward\nwo\jsasync\node_modules\openweather-apis\index.js:162:40
This is clearly a bug in the openweather-apis library. Report it. You hardly will be able to work around it. The library will need to check whether jsonObj and jsonObj.main exist before attempting to access .temp on it, and it should call your callback with an error if the jsonObj doesn't look as expected.

How can I trigger error object in lambda.invoke

How can i trigger error object in lambda.invoke
lambda.invoke(params, (err, data) => {
if (err) {
reject(.... // I would have expected below error to show up here
else
// error shows up inside the data.Payload
const result = data.Payload
// I have to create a condition to check for the error
resolve(result);
in the called lambda, i've tried the following:
exports.handler = ( event, context, callback) => {
if (payload === '')
context.done(new Error('my error message');
}
however, the error object ends up in the payload, where I have to check for it instead of going into a catch or other error path.
Instead of using the "older way" to stop execution you should use the callback(error, [success]) method. So in your lambda being invoked try callback('my error message') and that should go into your if block. You can read the documentation here for more info. I believe that in the "older way" of doing things context.done() is considered successful and context.fail() was used to signify an error.

How do I fail a test in Jest when an uncaught promise rejection occurs?

I'm working on adding test coverage to a Node project I'm working on using Jest. The code I'm testing is throwing errors within promises resulting in an UnhandledPromiseRejectionWarning message being logged to the console.
While writing tests, I can pretty easily identify these issues and resolve them, but these warnings aren't actually causing Jest to mark the tests as failed, so our CI won't catch it. I've searched around for any suggestions and haven't found much.
I did find in Node's documentation that you can catch these warnings and handle them...
process.on('unhandledRejection', (error) => {
throw error; // Or whatever you like...
});
So it seems like it would be pretty straightforward to add this code into my test cases. After all, an Error thrown within the test should cause the test to fail...
describe('...', () => {
it('...', () => {
process.on('uncaughtRejection', (error) => {
throw error;
});
// the rest of my test goes here
});
});
Unfortunately the behavior I'm seeing is that the error does get thrown, but Jest doesn't catch it and fail the test. Instead, Jest crashes with this error and the tests don't continue to run. This isn't really desirable, and seems like incorrect behavior.
Throwing an error outside of the uncaughtRejection handler works as expected: Jest logs the thrown error and fails the test, but doesn't crash. (i.e. the test watcher keeps watching and running tests)
The way I've approached this is very much tied into the way I write my functions - basically, any function that uses promises should return a promise. This allows whatever code calls that function to handle catching errors in any way it sees fit. Note that this is my approach and I'm not going to claim this is the only way to do things.
For example... Imagine I'm testing this function:
const myFunction = () => {
return doSomethingWithAPromise()
.then(() => {
console.log('no problems!');
return true;
});
};
The test will look something like this:
describe('...', () => {
it('...', () => {
return myFunction()
.then((value) => {
expect(value).toBe(true);
});
});
});
Which works great. Now what happens if the promise is rejected? In my test, the rejected promise is passed back to Jest (because I'm returning the result of my function call) and Jest can report on it.
If, instead, your function does not return a promise, you might have to do something like this:
const myOtherFunction = () => {
doSomethingWithAPromise()
.then(() => {
console.log('no problems!');
return true;
})
.catch((err) => {
// throw the caught error here
throw err;
});
};
Unlike the example above, there is no (direct) way for Jest to handle a rejected promise because you're not passing the promise back to Jest. One way to avoid this might be to ensure there is a catch in the function to catch & throw the error, but I haven't tried it and I'm not sure if it would be any more reliable.
Include the following content in Jest's setupFiles:
if (!process.env.LISTENING_TO_UNHANDLED_REJECTION) {
process.on('unhandledRejection', reason => {
throw reason
})
// Avoid memory leak by adding too many listeners
process.env.LISTENING_TO_UNHANDLED_REJECTION = true
}
Courtesy of stipsan in https://github.com/facebook/jest/issues/3251#issuecomment-299183885.
module:
export function myPromise() {
return new Promise((resolve, reject) => {
const error = new Error('error test');
reject(error);
});
}
test:
import { myPromise } from './module';
it('should reject the promise', () => {
expect.assertions(1);
const expectedError = new Error('error test');
myPromise().catch((error) => {
expect(error).toBe(expectedError);
});
From the node documentation site we can see that The process object is an instance of EventEmitter.
Using the emit function from process we can trigger the errors like uncaughtRejection and uncaughtException programmatically when needed.
it("should log the error", () => {
process.emit("unhandledRejection");
...
const loggerInfo = jest.spyOn(logger, "info");
expect(loggerInfo).toHaveBeenCalled();
});
Not sure if this helps, but you can also assert for promise rejections as such
index.js
module.exports = () => {
return Promise.reject('it didnt work');
}
index.spec.js
const thing = require('../src/index');
describe('rejected promise', () => {
it('should reject with a reason', ()=> {
return expect(thing()).rejects.toEqual('it didnt work');
});
});

Chai expected [Function] to throw an (error) not passing the test (Using Node)

The question:
I'm using Chai to do the tests and I seem to be stuck on testing an expected error:
Chai expected [Function] to throw an (error)
Current code:
Here's the code of the test:
describe('Do something', function () {
it('should remove a record from the table', function (done) {
storage.delete(ID, done);
});
it('should throw an error when the lookup fails', function () {
expect(storage.delete.bind(storage, ID)).to.throw('Record not found');
});
});
Here's the code of the function:
delete: function (id, callback) {
// Generate a Visitor object
visitor = new Visitor(id);
/* Delete the visitor that matches the queue an
cookie provided. */
tableService.deleteEntity(function (error, response) {
// If successful, go on.
if (!error) {
// Do something on success.
}
// If unsuccessful, log error.
else {
if (error.code === 'ResourceNotFound') {
throw new Error('Record not found');
}
// For unexpected errros.
else {
throw new Error('Table service error (delete): ' + error);
}
}
if (callback) callback();
});
},
Attempted solutions:
I've tried multiple variations of calling expect function (including calling anonymous function:
expect(function() {storage.delete(ID);}).to.throw('Record not found');
Bind, as provided in the example,
and the basic one of
expect(storage.delete(ID)).to.throw('Record not found');
I've also tried substituting the throw parameter from 'Record not found' to multiple things including directing the input to an already created error (Error), and creating a new error in the parameter (new Error('Record not found'));
Possible causes:
I have a suspicion that the error is not being thrown because it takes a while for the test to communicate with the database to delete the record, however I am not sure of how I could remedy that.
Additionally, it seems that the test that runs right after this one actually returns the error that was supposed to be returned on THIS test.
Given (from comments) that tableService.deleteEntity is asynchronous, it is impossible to test that throw. And the code itself is invalid. Because the thrown exception won't be caught, it will be unhandled as it was thrown in a different tick. Read more about Asynchronous error handling in JavaScript and unhandled exceptions in Node.js
In other words such a function cannot be tested for throwing errors:
function behaveBad(){
setTimeout(function(){
throw new Error('Bad. Don\'t do this');
}, 50);
}

correct way to break promise chain on first rejection [duplicate]

I am still fairly new to promises and am using bluebird currently, however I have a scenario where I am not quite sure how to best deal with it.
So for example I have a promise chain within an express app like so:
repository.Query(getAccountByIdQuery)
.catch(function(error){
res.status(404).send({ error: "No account found with this Id" });
})
.then(convertDocumentToModel)
.then(verifyOldPassword)
.catch(function(error) {
res.status(406).send({ OldPassword: error });
})
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
So the behaviour I am after is:
Goes to get account by Id
If there is a rejection at this point, bomb out and return an error
If there is no error convert the document returned to a model
Verify the password with the database document
If the passwords dont match then bomb out and return a different error
If there is no error change the passwords
Then return success
If anything else went wrong, return a 500
So currently catches do not seem to stop the chaining, and that makes sense, so I am wondering if there is a way for me to somehow force the chain to stop at a certain point based upon the errors, or if there is a better way to structure this to get some form of branching behaviour, as there is a case of if X do Y else Z.
Any help would be great.
This behavior is exactly like a synchronous throw:
try{
throw new Error();
} catch(e){
// handle
}
// this code will run, since you recovered from the error!
That's half of the point of .catch - to be able to recover from errors. It might be desirable to rethrow to signal the state is still an error:
try{
throw new Error();
} catch(e){
// handle
throw e; // or a wrapper over e so we know it wasn't handled
}
// this code will not run
However, this alone won't work in your case since the error be caught by a later handler. The real issue here is that generalized "HANDLE ANYTHING" error handlers are a bad practice in general and are extremely frowned upon in other programming languages and ecosystems. For this reason Bluebird offers typed and predicate catches.
The added advantage is that your business logic does not (and shouldn't) have to be aware of the request/response cycle at all. It is not the query's responsibility to decide which HTTP status and error the client gets and later as your app grows you might want to separate the business logic (how to query your DB and how to process your data) from what you send to the client (what http status code, what text and what response).
Here is how I'd write your code.
First, I'd get .Query to throw a NoSuchAccountError, I'd subclass it from Promise.OperationalError which Bluebird already provides. If you're unsure how to subclass an error let me know.
I'd additionally subclass it for AuthenticationError and then do something like:
function changePassword(queryDataEtc){
return repository.Query(getAccountByIdQuery)
.then(convertDocumentToModel)
.then(verifyOldPassword)
.then(changePassword);
}
As you can see - it's very clean and you can read the text like an instruction manual of what happens in the process. It is also separated from the request/response.
Now, I'd call it from the route handler as such:
changePassword(params)
.catch(NoSuchAccountError, function(e){
res.status(404).send({ error: "No account found with this Id" });
}).catch(AuthenticationError, function(e){
res.status(406).send({ OldPassword: error });
}).error(function(e){ // catches any remaining operational errors
res.status(500).send({ error: "Unable to change password" });
}).catch(function(e){
res.status(500).send({ error: "Unknown internal server error" });
});
This way, the logic is all in one place and the decision of how to handle errors to the client is all in one place and they don't clutter eachother.
.catch works like the try-catch statement, which means you only need one catch at the end:
repository.Query(getAccountByIdQuery)
.then(convertDocumentToModel)
.then(verifyOldPassword)
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error) {
if (/*see if error is not found error*/) {
res.status(404).send({ error: "No account found with this Id" });
} else if (/*see if error is verification error*/) {
res.status(406).send({ OldPassword: error });
} else {
console.log(error);
res.status(500).send({ error: "Unable to change password" });
}
});
I am wondering if there is a way for me to somehow force the chain to stop at a certain point based upon the errors
No. You cannot really "end" a chain, unless you throw an exception that bubbles until its end. See Benjamin Gruenbaum's answer for how to do that.
A derivation of his pattern would be not to distinguish error types, but use errors that have statusCode and body fields which can be sent from a single, generic .catch handler. Depending on your application structure, his solution might be cleaner though.
or if there is a better way to structure this to get some form of branching behaviour
Yes, you can do branching with promises. However, this means to leave the chain and "go back" to nesting - just like you'd do in an nested if-else or try-catch statement:
repository.Query(getAccountByIdQuery)
.then(function(account) {
return convertDocumentToModel(account)
.then(verifyOldPassword)
.then(function(verification) {
return changePassword(verification)
.then(function() {
res.status(200).send();
})
}, function(verificationError) {
res.status(406).send({ OldPassword: error });
})
}, function(accountError){
res.status(404).send({ error: "No account found with this Id" });
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
I have been doing this way:
You leave your catch in the end. And just throw an error when it happens midway your chain.
repository.Query(getAccountByIdQuery)
.then((resultOfQuery) => convertDocumentToModel(resultOfQuery)) //inside convertDocumentToModel() you check for empty and then throw new Error('no_account')
.then((model) => verifyOldPassword(model)) //inside convertDocumentToModel() you check for empty and then throw new Error('no_account')
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch((error) => {
if (error.name === 'no_account'){
res.status(404).send({ error: "No account found with this Id" });
} else if (error.name === 'wrong_old_password'){
res.status(406).send({ OldPassword: error });
} else {
res.status(500).send({ error: "Unable to change password" });
}
});
Your other functions would probably look something like this:
function convertDocumentToModel(resultOfQuery) {
if (!resultOfQuery){
throw new Error('no_account');
} else {
return new Promise(function(resolve) {
//do stuff then resolve
resolve(model);
}
}
Probably a little late to the party, but it is possible to nest .catch as shown here:
Mozilla Developer Network - Using Promises
Edit: I submitted this because it provides the asked functionality in general. However it doesn't in this particular case. Because as explained in detail by others already, .catch is supposed to recover the error. You can't, for example, send a response to the client in multiple .catch callbacks because a .catch with no explicit return resolves it with undefined in that case, causing proceeding .then to trigger even though your chain is not really resolved, potentially causing a following .catch to trigger and sending another response to the client, causing an error and likely throwing an UnhandledPromiseRejection your way. I hope this convoluted sentence made some sense to you.
Instead of .then().catch()... you can do .then(resolveFunc, rejectFunc). This promise chain would be better if you handled things along the way. Here is how I would rewrite it:
repository.Query(getAccountByIdQuery)
.then(
convertDocumentToModel,
() => {
res.status(404).send({ error: "No account found with this Id" });
return Promise.reject(null)
}
)
.then(
verifyOldPassword,
() => Promise.reject(null)
)
.then(
changePassword,
(error) => {
if (error != null) {
res.status(406).send({ OldPassword: error });
}
return Promise.Promise.reject(null);
}
)
.then(
_ => res.status(200).send(),
error => {
if (error != null) {
console.error(error);
res.status(500).send({ error: "Unable to change password" });
}
}
);
Note: The if (error != null) is a bit of a hack to interact with the most recent error.
I think Benjamin Gruenbaum's answer above is the best solution for a complex logic sequence, but here is my alternative for simpler situations. I just use an errorEncountered flag along with return Promise.reject() to skip any subsequent then or catch statements. So it would look like this:
let errorEncountered = false;
someCall({
/* do stuff */
})
.catch({
/* handle error from someCall*/
errorEncountered = true;
return Promise.reject();
})
.then({
/* do other stuff */
/* this is skipped if the preceding catch was triggered, due to Promise.reject */
})
.catch({
if (errorEncountered) {
return;
}
/* handle error from preceding then, if it was executed */
/* if the preceding catch was executed, this is skipped due to the errorEncountered flag */
});
If you have more than two then/catch pairs, you should probably use Benjamin Gruenbaum's solution. But this works for a simple set-up.
Note that the final catch only has return; rather than return Promise.reject();, because there's no subsequent then that we need to skip, and it would count as an unhandled Promise rejection, which Node doesn't like. As is written above, the final catch will return a peacefully resolved Promise.
I wanted to preserve the branching behaviour that Bergi's answer had, yet still provide the clean code structure of unnested .then()'s
If you can handle some ugliness in the machinery that makes this code work, the result is a clean code structure similar to non-nested chained .then()'s
One nice part of structuring a chain like this, is that you can handle all the potential results in one place by chainRequests(...).then(handleAllPotentialResults) this might be nice if you need to hide the request chain behind some standardised interface.
const log = console.log;
const chainRequest = (stepFunction, step) => (response) => {
if (response.status === 200) {
return stepFunction(response, step);
}
else {
log(`Failure at step: ${step}`);
return response;
}
};
const chainRequests = (initialRequest, ...steps) => {
const recurs = (step) => (response) => {
const incStep = step + 1;
const nextStep = steps.shift();
return nextStep ? nextStep(response, step).then(chainRequest(recurs(incStep), incStep)) : response;
};
return initialRequest().then(recurs(0));
};
// Usage
async function workingExample() {
return await chainRequests(
() => fetch('https://jsonplaceholder.typicode.com/users'),
(resp, step) => { log(`step: ${step}`, resp); return fetch('https://jsonplaceholder.typicode.com/posts/'); },
(resp, step) => { log(`step: ${step}`, resp); return fetch('https://jsonplaceholder.typicode.com/posts/3'); }
);
}
async function failureExample() {
return await chainRequests(
() => fetch('https://jsonplaceholder.typicode.com/users'),
(resp, step) => { log(`step: ${step}`, resp); return fetch('https://jsonplaceholder.typicode.com/posts/fail'); },
(resp, step) => { log(`step: ${step}`, resp); return fetch('https://jsonplaceholder.typicode.com/posts/3'); }
);
}
console.log(await workingExample());
console.log(await failureExample());
The idea is there, but the interface exposed could probably use some tweaking.
Seeing as this implementation used curried arrow functions, the above could potentially be implemented with more direct async/await code

Categories

Resources