Home > Software design >  Node-Fetch unhandled promise rejection (can't catch it)
Node-Fetch unhandled promise rejection (can't catch it)

Time:07-19

I'm struggling for 2 days on this one so I try asking here:

I have a nodejs script using node-fetch to make queries ton an API. However, I've tried adding catch blocks everywhere but it seems I didn't suceeded in ahndling the error.

Here is my function:

fetchUrl.get = async (url, params = false, headers = false) => {
        let defaultOptions = {
            method: "GET",
        };
    
        let finalUrl = new URL(url);
        Object.keys(params).forEach((key) =>
            finalUrl.searchParams.append(key, params[key])
        );
    
        let finalHeaders = {};
    
        if (headers != null && headers != false && Object.keys(headers).length > 0) {
            Object.keys(headers).forEach((headerKey) => {
                finalHeaders[headerKey] = headers[headerKey];
            });
        }
    
        defaultOptions["headers"] = finalHeaders;
    
        let result = null;
    
        try {
            result = await fetch(finalUrl, defaultOptions)
                .then((res) => {
                    if (res.status == 200) {
                        return {
                            success: true,
                            text: res.text(),
                        };
                    } else {
                        console.log("ERROR during Fetch: "   res.status);
                        console.error(finalUrl);
                        console.error(params);
                        res.text().then((err) => {
                            console.error(err);
                        });
                        return {
                            success: false,
                        };
                    }
                })
                .then((resParsed) => {
                    if (resParsed.success) {
                        return resParsed.text;
                    } else {
                        return false;
                    }
                });
        } catch (err) {
            throw err;
        }
    
        return result;
    };

And this is the error I get:

(node:2272) UnhandledPromiseRejectionWarning: FetchError: request to http://gdsfdfs.com/ failed, reason: getaddrinfo ENOTFOUND gdsfdfs.com
    at ClientRequest.<anonymous> (file:///home/kashnars/pearlv2/node_modules/node-fetch/src/index.js:108:11)
    at ClientRequest.emit (events.js:375:28)
    at Socket.socketErrorListener (_http_client.js:475:9)
    at Socket.emit (events.js:375:28)
    at emitErrorNT (internal/streams/destroy.js:106:8)
    at emitErrorCloseNT (internal/streams/destroy.js:74:3)
    at processTicksAndRejections (internal/process/task_queues.js:82:21)
(node:2272) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 50)

I know the URL is wrong, it's just for testing purposes. I need to catch the error.

Someone having the solution?

Thanks in advance,

CodePudding user response:

If you rethrow the exception after catching it, then it makes the caller error out (in your case ClientRequest.emit) so either dont rethrow it, or handle it in the caller.

That being said you should not use await and then simultaneously, use one of them (I strongly advise for await).

Basically your code could be simplified to this:

try {
  const result = await fetch(finalUrl, defaultOptions);
  return result.status == 200 ? result.text() : false;
}
catch(e) {
  console.log(e);
}

CodePudding user response:

The issue is that you throw an error, which is a Promise rejection in an async function

The calling function needs to handle the rejection

Now, since all you do in the catch is rethrow the error, no need to use try/catch at all

More simplifiction of your code is possible - but, basically, from the await it should go like

const res = await fetch(finalUrl, defaultOptions);
if (res.status == 200) {
    return res.text();
}
console.log("ERROR during Fetch: "   res.status);
console.log(finalUrl);
console.log(params);
const err = await res.text();
console.error(err);
return false;

with no try/catch

Alternatively, if you want this function to handle the network error, and return false, just like when status !== 200

try {
    const res = await fetch(finalUrl, defaultOptions);
    if (res.status == 200) {
        return res.text();
    }
    console.log("ERROR during Fetch: "   res.status);
    console.log(finalUrl);
    console.log(params);
    const err = await res.text();
    throw err;
} catch(err) {
    console.error(err);
    return false;
}

as a bonus, the code above the try { or await fetch can be simplified to

fetchUrl.get = async (url, params = false, headers = false) => {
    const defaultOptions = { 
        method: "GET",
        headers: {...(headers ?? {}) }
    };
    
    const finalUrl = new URL(url);
    Object.entries(params ?? {}).forEach(([key, value]) => {
        finalUrl.searchParams.append(key, value)
    });
  • Related