md-y/mangadex-full-api

UnhandledPromiseRejectionWarning whenever there's an issue with mangadex's api

Closed this issue · 2 comments

To reproduce:

const https = require("https");

// Monkey patch the "get" request to return a 500 error
// This is to simulate when mangadex goes down
https.get = (_url, _options, callback) => {
    callback({
        "headers": {},
        "statusCode": 500,
    });

    return {};
};

const api = require("mangadex-full-api");

api.agent.login(process.env.USER, process.env.PASSWORD, false).then(async () => {
    var chapter = await api.Chapter.get(208447);

    console.log(chapter.pages);
});

With the above I get the following error:

(node:73533) UnhandledPromiseRejectionWarning: MangaDex is currently unavailable or in DDOS mitigation mode. (Status code 500)
    at emitUnhandledRejectionWarning (internal/process/promises.js:151:15)
    at processPromiseRejections (internal/process/promises.js:211:11)
    at processTicksAndRejections (internal/process/task_queues.js:98:32)
(node:73533) 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: 2)
(node:73533) [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.
    at emitDeprecationWarning (internal/process/promises.js:161:11)
    at processPromiseRejections (internal/process/promises.js:213:13)
    at processTicksAndRejections (internal/process/task_queues.js:98:32)

Problem description:

When I use the above code (without the monkey patch) and mangadex is down, I want to be able to catch these errors and retry.
Instead, when something goes wrong with the API request I get an UnhandledPromiseRejectionWarning, which seems to be uncatchable.

My own investigation:

I've gone through the code and found that this particular issue is because you use await on Util.getJSON here.

This throws an exception instead of calling reject like the rest of your code.

I'm not 100% sure what a good solution would be to this problem.
Simply doing the following just moves the error somewhere else:

diff --git a/src/structure/chapter.js b/src/structure/chapter.js
index 87f7017..b1bf008 100644
--- a/src/structure/chapter.js
+++ b/src/structure/chapter.js
@@ -129,7 +129,7 @@ class Chapter extends APIObject {
             if (!id) reject("No id specified or found.");

             // API v2
-            let res = await Util.getJSON(api + id.toString());
+            let res = Util.getJSON(api + id.toString()).catch(reject);^M
             if (!res) reject("Invalid API response");
             if (res.status !== "OK") reject("API responsed with an error: " + res.message);

I think probably picking either async/await or raw promises but not both is probably the issue here,

It looks like you're handling the failed JSON parsing in the Util.getJSON call and are rejecting there. As far as I can tell you'll never fall into the if(!res) scenario as the Util.getJSON will reject and cause an unhandled promise rejection error to be thrown. The following should resolve the problem (note I haven't tested any of this) and you can decide whether the !res case is necessary although probably a nice thing to keep anyway.

index 87f7017..07b1435 100644
--- a/src/structure/chapter.js
+++ b/src/structure/chapter.js
@@ -129,12 +129,17 @@ class Chapter extends APIObject {
             if (!id) reject("No id specified or found.");

             // API v2
-            let res = await Util.getJSON(api + id.toString());
-            if (!res) reject("Invalid API response");
-            if (res.status !== "OK") reject("API responsed with an error: " + res.message);
+            try {
+                let res = await Util.getJSON(api + id.toString());
+                if (!res) reject("Invalid API response");
+                if (res.status !== "OK") reject("API responsed with an error: " + res.message);
+
+                this._parse(res.data);
+                resolve(this);
+            } catch (err) {
+                reject(err)
+            }

-            this._parse(res.data);
-            resolve(this);
         });
     }
md-y commented

Fixed in Release 4.3.1