Promise remains unresolved even after handling all cases - node.js

I have been writing on a Discord.JS Bot for quite a bit now, and every now and then it seems to throw me a random error / warning in console after executing one of its chat commands
(specifically !clear).
Now, as I already stated, the message I get in my console is a warning, not an actual error, so that's not the main problem I have;
My problem lies in the execution of the command on Discord's side: Because of the unresolved, rejected promise, it will not execute !clear at all, leaving all messages including the command itself behind. Here's a snippet of my code:
if (member.hasPermission("MANAGE_MESSAGES")) {
channel.fetchMessages({ limit: 100 })
.then(messages => {
console.log(`Deleting ${messages.size} messages...`);
channel.bulkDelete(messages).then(res => {}, err => {});
channel.sendEmbed({
// Success Message
}).then(msg => msg.delete(10000), err => console.log(err));
}, err => { console.log(err) })
} else {
channel.sendEmbed({
// Permission Message
}).then(msg => msg.delete(10000), err => { console.log(err) });
}
As you can see, I resolved both the success and the failure state of every Promise, yet I will still see the following warning in console:
(node:14768) Error: Bad Request Sometimes also throws Not Found
-- Stack Trace that only includes internal Node.JS errors --
(node:14768) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
-- More Stack Trace not regarding any of my own code --
If any of you need additional code provided to answer the question, feel free to ask me and I will do so. Also, I can't +rep answers yet, but I always appreciate 'em :)

You aren't handling the msg.delete(10000) rejection. You should handle it like this:
channel.sendEmbed({
// Success Message
}).then(msg => msg.delete(10000)).catch(err => console.log(err));

Related

Unhandled Promise Rejection: AxiosError: Network Error

Working on a MERN stack project. When trying to access the site on localhost on iPhone Posts are posts are not loading. Working fine on adnroid devices.
Screenshot of error
const fetchFeedPosts = async () => {
const URL = `${BASE__URL}api/posts/feed/${LOGGED__IN__USER}`;
await axios.get(URL)
.then((response) => setFeedPosts([...response.data].reverse()))
.catch((e) => console.log(e.response));
}
fetchFeedPosts()
What the error means
When an Error is thrown (e.g. throw new Error()) it can
be catched locally (e.g. try{...} catch(err) { /** here */ })
or be passed on to the calling function. And in that fashion it bubbles up from caller to caller until it reaches a catch somewhere.
However, if it continues to bubble up, and there's nothing that captures it by the time it reaches the root of your application or code, then that will result in a so-called "Unhandled" error.
Now, as you may know, promises are more like jobs that drift around. They aren't called from the root of your application. But as they bubble up they can also reach a similar root-point, in which case they become "Unhandled Promise rejections".
What to do about it
Unhandled errors or rejections are bad practice though. Errors should be caught somewhere. And without catching them, you can't really know what has caused the error to happen in the first place.
In most cases, you can catch them with a .catch() function, (e.g. yourPromise.catch((err) => {console.err(err)}))
In case your promise is handled in an async function and waited for with an await keyword, then it's slightly different. In that case it makes more sense to use a try-catch block to capture your error.
How to apply it to your code
So, the first way of doing it would be to use the .catch() function
axios.get(URL)
.then((response) => setFeedPosts([...response.data].reverse()))
.catch((err) => console.error(err));
The alternative is to use the await syntax with a try-catch. If you want to use this syntax, you have to put the async keyword before your function.
try {
const response = await axios.get(URL)
setFeedPosts([...response.data].reverse()))
} catch (err) {
console.log(err);
}
Sure, you could mix the 2, but in most cases that would be rather strange.

UnhandledPromiseRejectionWarning Persists Even After Chaining a .catch()

My system consists of an Angular UI and a Node API. The UI submits a file to the API for processing, then gets the result back. This all works - however - the API sometimes fails at processing unexpected data.
I want to be able to catch the error(s) when they arise, stop execution so they won't screw up the UI, then send a message back to UI.
Here is my code so far:
const IncomingForm = require('formidable').IncomingForm;
asynch function myApi(req, res)
{
try // (1)
{
var form = new IncomingForm(...);
form.on('file', async(field, file) =>
{
const [result] = await sometimesBad(inParam); // (2) attach .catch(...);
...
res.send({goodFinal}); // execution should not reach here if error occurs before
});
form.on('end', ()=> {})
form.parse(req)
}
catch (erApi) // (3)
{
... // (4)
}
}
async function sometimesBad(x)
{
try // (5)
{
... lines of code could have run-time error depends on x ...
return goodResult;
}
catch(err2) // (6)
{
... // (7)
}
}
Currently, after hours of searching and trial and error, I:
am able to send a message back by chaining a .catch() at (2)
am unable to stop the execution via any combination of (1), (3), (4), (5), (6), (7), including the use of next(), throw new Error(), await Promise.reject(), return Promise.reject().
am always getting UnhandledPromiseRejectionWarning: Unhandled promise rejection.
Node version: 14.9
Update: In addition to accepted answer, there is no need to have (5), (6), (7).
In your code if (2) throws the error indeed is not handled. To handle it, you need to wrap the code inside async (field, file) => ... into try / catch, similar to how you did on the top level of middleware, and inside the catch you do next(error). Also add default error handler after all routes in your app. See How to return error to the client client without making node server crash? regarding that.
You can stop unhandledRejection(s) from crashing your app by handling them. However, if you fail to handle them using catch blocks, you can also watch for events on the process.
Code Example from the Docs:
process.on('unhandledRejection', (reason, promise) => {
console.log('Unhandled Rejection at:', promise, 'reason:', reason);
// Application specific logging, throwing an error, or other logic here
});
somePromise.then((res) => {
return reportToUser(JSON.pasre(res)); // Note the typo (`pasre`)
}); // No `.catch()` or `.then()`
Alternatively, you can make your sometimesBad function return a Promise, which would cause all errors happening inside the Promise body to be thrown, which can then be handled in the catch block of the caller.

Prevent "Unhandled promise rejection" error

In my server app I want to return a "forbidden" value when the user has no permissions for the endpoint.
To this end I create a rejected promise for reuse:
export const forbidden = Promise.reject(new Error('FORBIDDEN'))
and then elsewhere in the app:
import {forbidden} from './utils'
...
resolve: (root, {post}, {db, isCollab}) => {
if (!isCollab) return forbidden
return db.posts.set(post)
},
However, when I start my app I get the warning
(node:71620) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: FORBIDDEN
(node:71620) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
How can I tell Node that this Promise is fine to be unhandled?
I create a rejected promise for reuse
Well don't, it might be a lot easier to just create a function for reuse:
export function forbidden() { return Promise.reject(new Error('FORBIDDEN')); }
That will also get you an appropriate stack trace for the error every time you call it.
How can I tell Node that this Promise is fine to be unhandled?
Just handle it by doing nothing:
export const forbidden = Promise.reject(new Error('FORBIDDEN'));
forbidden.catch(err => { /* ignore */ }); // mark error as handled
(and don't forget to include the comment about the purpose of this seemingly no-op statement).
I wouldn't recommend using the return statement to provide an Error - this is ignoring the exact intention of throw!
Simply use:
if (!isCollab) throw new Error('FORBIDDEN');
If you don't want a stack trace there's no need to over-engineer - simply do:
if (!isCollab) throw 'FORBIDDEN';
If you need a message property to exist you can simply use:
if (!isCollab) throw { message: 'FORBIDDEN' };
(Note: I recommend against throwing anything other than an instance of Error! You'll regret it later when things break and you need to debug)
OP's usage is not completely described, but the OP's comment "BTW I didn't want to create a stack trace for every forbidden error because I don't want to leak details about my app. So I prefer to create the rejection only once." leads me to believe that at least part of the OP's motivation is to prevent info leakage from unhandled rejections of forbidden.
Returning a rejected (but defused) promise behaves differently in a sync vs. an async function. In the former the promise is returned verbatim. In the latter it is rewrapped in a promised and automatically rethrown (equivalent to throwing from inside the function). Whichever use was intended, it makes the program harder to understand.(Wrapping the Promise to be returned in an object or array would solve that problem).
Difference in behavior between sync and async funcs when returning forbidden :
async function test(){
try {
let a = await (async()=>{return forbidden;})();
} catch(e){console.log(e.message);} // outputs: 'FORBIDDEN'
try {
let a = (()=>{return forbidden;})();
// error undetected
} catch(e){console.log(e.message);} // never reaches here !!!
console.log("something else"); // outputs: something else
let a=(()=>{return forbidden;})(); // UHR + '#<Promise>' + no addr
console.log("something else"); // outputs: something else
await (async()=>{return forbidden;})(); // UHR + '#<Promise>' + no addr leak}
}
test();
Regardless of the the OP's usuage, leakage of program info from unhandled-rejections is a valid concern.
The below factory function makeError would provide a general solution, and it builds on the OP's original inspiration:
const verboten=new Error('verbotten');
const makeError = () => verboten;
async function test2(){
try {
await (async()=>{throw makeError();})();
} catch(e){console.log(e.message);} // outputs: 'verboten'
// uncomment the following to trigger UHR (unhandled rejection)
//await (async()=>{throw makeError();})(); // UHR + 'verboten' + no addr leak
}
Note that makeError returns the constant object verboten, rather than itself. (Yes, that is allowed, although it is rarely used.) So the stack trace is a fixed value, unrelated to the error location in the program, just like the original OP's forbidden.
That's fine for the release version, but a minor change to makeError could be made for a development version, where seeing the stack is useful:
const makeError = Error;

How to track down the source of UnhandledPromiseRejectionWarning in node 8.2.1 [duplicate]

Node.js from version 7 has async/await syntactic sugar for handling promises and now in my code the following warning comes up quite often:
(node:11057) UnhandledPromiseRejectionWarning: Unhandled promise
rejection (rejection id: 1): ReferenceError: Error: Can't set headers
after they are sent.
(node:11057) DeprecationWarning: Unhandled promise rejections are
deprecated. In the future, promise rejections that are not handled
will terminate the Node.js process with a non-zero exit code.
Unfortunately there's no reference to the line where the catch is missing.
Is there any way to find it without checking every try/catch block?
listen unhandledRejection event of process.
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
// application specific logging, throwing an error, or other logic here
});
The correct way to show a full stacktrace for unhandled ES6 Promise rejections, is to run Node.js with the --trace-warnings flag. This will show the full stacktrace for every warning, without having to intercept the rejection from within your own code. For example:
node --trace-warnings app.js
Ensure that the trace-warnings flag comes before the name of your .js file! Otherwise, the flag will be interpreted as an argument to your script, and it will be ignored by Node.js itself.
If you want to actually handle unhandled rejections (eg. by logging them), then you might want to use my unhandled-rejection module instead, which catches all the unhandled rejections for every major Promises implementation that supports it, with a single event handler.
That module supports Bluebird, ES6 Promises, Q, WhenJS, es6-promise, then/promise, and anything that conforms to any of the unhandled rejection specifications (full details in the documentation).
Logging with stack trace
If you are looking for more of a helpful error message. Try adding this to your node file. It should display the full stack trace where your crash is happening.
process.on('unhandledRejection', (error, p) => {
console.log('=== UNHANDLED REJECTION ===');
console.dir(error.stack);
});
This module allowed me to track down the culprit promise(s):
https://www.npmjs.com/package/trace-unhandled
Install
npm i trace-unhandled
Include in code
require('trace-unhandled/register');
#Jeremy I had same result, the reason variable provided by
process.on('unhandledRejection', (reason, p) => {});
wasn't defined and it take me time to figure out that there were promise rejection providing nothing in my code, typically:
new Promise((resolve reject) => {
const client = net.connect(options)
client.on("connect", () => {
resolve()
})
client.on("error", () => {
reject()
})
})
the problem is that you reject with nothing, to get trace you have to provide error, like this
new Promise((resolve reject) => {
const client = net.connect(options)
client.on("connect", () => {
resolve()
})
client.on("error", (err) => {
reject(err)
})
})
and if you don't have error you can provide one yourself, even if empty, it will give a stack trace
reject(new Error())
If you need to find where the error was throwed from, look in your code for Promise with empty rejection

How to find which promises are unhandled in Node.js UnhandledPromiseRejectionWarning?

Node.js from version 7 has async/await syntactic sugar for handling promises and now in my code the following warning comes up quite often:
(node:11057) UnhandledPromiseRejectionWarning: Unhandled promise
rejection (rejection id: 1): ReferenceError: Error: Can't set headers
after they are sent.
(node:11057) DeprecationWarning: Unhandled promise rejections are
deprecated. In the future, promise rejections that are not handled
will terminate the Node.js process with a non-zero exit code.
Unfortunately there's no reference to the line where the catch is missing.
Is there any way to find it without checking every try/catch block?
listen unhandledRejection event of process.
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
// application specific logging, throwing an error, or other logic here
});
The correct way to show a full stacktrace for unhandled ES6 Promise rejections, is to run Node.js with the --trace-warnings flag. This will show the full stacktrace for every warning, without having to intercept the rejection from within your own code. For example:
node --trace-warnings app.js
Ensure that the trace-warnings flag comes before the name of your .js file! Otherwise, the flag will be interpreted as an argument to your script, and it will be ignored by Node.js itself.
If you want to actually handle unhandled rejections (eg. by logging them), then you might want to use my unhandled-rejection module instead, which catches all the unhandled rejections for every major Promises implementation that supports it, with a single event handler.
That module supports Bluebird, ES6 Promises, Q, WhenJS, es6-promise, then/promise, and anything that conforms to any of the unhandled rejection specifications (full details in the documentation).
Logging with stack trace
If you are looking for more of a helpful error message. Try adding this to your node file. It should display the full stack trace where your crash is happening.
process.on('unhandledRejection', (error, p) => {
console.log('=== UNHANDLED REJECTION ===');
console.dir(error.stack);
});
This module allowed me to track down the culprit promise(s):
https://www.npmjs.com/package/trace-unhandled
Install
npm i trace-unhandled
Include in code
require('trace-unhandled/register');
#Jeremy I had same result, the reason variable provided by
process.on('unhandledRejection', (reason, p) => {});
wasn't defined and it take me time to figure out that there were promise rejection providing nothing in my code, typically:
new Promise((resolve reject) => {
const client = net.connect(options)
client.on("connect", () => {
resolve()
})
client.on("error", () => {
reject()
})
})
the problem is that you reject with nothing, to get trace you have to provide error, like this
new Promise((resolve reject) => {
const client = net.connect(options)
client.on("connect", () => {
resolve()
})
client.on("error", (err) => {
reject(err)
})
})
and if you don't have error you can provide one yourself, even if empty, it will give a stack trace
reject(new Error())
If you need to find where the error was throwed from, look in your code for Promise with empty rejection

Resources