How to differentiate between operational and programmer errors in promise chains?

How to differentiate between operational and programmer errors in promise chains?



So I want to know how to make sure that my Node application will crash if it comes upon a programmer error(undefined variable, reference error, syntax error...). However, if I am using promise chains then the final catch() will catch all possible errors including programmer errors.


catch()



For example:


PromiseA()
.then((result) =>
foo.bar(); //UNDEFINED FUNCTION HERE!!!!!
return PromiseB(result);
)
.catch(
//handle errors here
)



Now the catch() statement will also catch the really bad error of an undefined function and then try to handle it. I need a way for my program to crash when it comes up against errors like these.


catch()



EDIT: I also just realized that even if I throw an error in the last catch it will just be consumed by the promise chain :-[. How am I supposed to deal with that?





This is the same problem as in Javascript without using promises, is it not?
– djechlin
Aug 22 at 22:33





Throw back any errors you aren't handling
– MinusFour
Aug 22 at 22:35





How would I differentiate between them elegantly? Without long if else chains? There could be any number of types of operational errors that come from PromiseA or PromiseB.
– Joshua Avery
Aug 22 at 22:36






With a Map, an object or even a switch.
– MinusFour
Aug 22 at 22:40


Map





An example please?
– Joshua Avery
Aug 22 at 22:41




2 Answers
2



Basically, what you want to do is to handle those errors that you can potentially recover from. These errors are usually something you throw in your code. For example, if an item is not found in a DB some libraries will throw an Error. They'll add a type property or some other property to differentiate the different type of errors.


Error


type



You can also potentially subclass the Error class and use instanceof to differentiate each error.


Error


instanceof


class myOwnError extends Error



Then:


Prom.catch(err =>
if(err instanceof myOwnError) /* handle error here */
else throw err;
);



If you want to avoid if/chains, you can use a switch on error.constructor:


switch


error.constructor


switch(err.constructor)
case myOwnError:
break;
case someOtherError:
break;
default:
throw err;



You can also use an a Map or regular objects by creating functions for each possible error and storing them. With a Map:


Map


Map


let m = new Map();
m.set(myOWnError, function(e) /*handle error here*/ );
m.set(myOtherError, function(e) /*handle other error here*/ );



Then just do:


Prom.catch(err =>
let fn = m.get(err.constructor);
if(fn) return fn(err);
else throw err;
);





Ok, so what you're saying is I need to check if that error was made by the library by checking the type property. Will I be able to find this in the library's documentation? Also if I throw an error within a catch() statement it will be consumed by the chain and will not crash my program. How do I fix this? Finally is it normal for me to be concerned about having these other types of exceptions or am I just being paranoid? I have never seen an example of someone trying to safeguard against those errors.
– Joshua Avery
Aug 22 at 23:21



catch()





Usually yes, they add extra information on the error objects they throw. Not all of them will though. If you throw an error within a catch and you never attached another catch to it then it will become an unhandled rejected promise. You can then do this if you want it to crash.
– MinusFour
Aug 22 at 23:29


catch


catch





So is it common practice for me to worry about this? Am I being paranoid? I have seen no examples of someone trying to safeguard against errors like this.
– Joshua Avery
Aug 22 at 23:37





Yes it is, no you aren't. People swallow errors with catch all the time and are left without any clue of what the heck just happened to their program.
– MinusFour
Aug 22 at 23:42



catch



Disclaimer: Below is a description what we do at the company I work. The package linked is written by us.



What we do is to catch all errors and sort them into programmer and operational errors.



We've made small library to help us: https://www.npmjs.com/package/oops-error



For promise chains we use:


import programmerErrorHandler from 'oops-error'

...
export const doSomething = (params) =>
somePromiseFunction().catch(programmerErrorHandler('failed to do something', params))



It marks the error as programmer error, adds 'failed to do something' as error message and adds the params as a context (for debugging later)



For errors that we know that can come up (person not found, validEmail, etc) we do something like


import Oops from 'oops-error'

export const sendEmail = (email) =>
if(!isValidEmail(email))
throw new Oops(
message: 'invalid email',
category: 'OperationalError',
context:
email,
,
)

...



At every level we show the error messages of Operational Errors. So a simple


.cath(e =>
if (e.category == 'OperationalError')
// handle the gracefully

else
throw e // We will tackle this later




And at the end of our request in express we have our final error handler, where catch the error, check if its operational and then show the error message, but not the actual context. If its a programmer error we stop the process (not ideal, but we don't want the user to keep messing with broken code)





Thanks, this makes me feel a bit better about not being completely paranoid.
– Joshua Avery
Aug 23 at 0:55






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)