Unhandled promise rejection, even though I’m pretty sure I’ve handled them all

Tags: , ,



I’ve written a node app that fetches data from an API, using multiple endpoints. I am also using proxies to do this.

I’m currently using socks-proxy-agent to create a https agent for my axios instances to use the proxy.

Here is the class that does all of this:

export class Checker {
    private region: Region
    private proxy: AxiosProxyConfig | false
    private client: AxiosInstance
    constructor(region: Region, proxy?: AxiosProxyConfig | false) {
        this.region = region;
        this.proxy = proxy;
        if (proxy) {
            const proxyOptions = `socks://${proxy.host}:${proxy.port}`;
            const httpsAgent = new SocksProxyAgent(proxyOptions);
            this.client = axios.create({ timeout: 5000, httpsAgent: httpsAgent });
        } else {
            this.client = axios.create({ timeout: 5000 });
        }
    }
    public check(account: Account): Promise<CheckResponse> {
        return new Promise((resolve, reject) => {
            this.client.post("xxx", {
                acr_values: "urn:riot:bronze",
                claims: "",
                client_id: "riot-client",
                nonce: 1,
                redirect_uri: "http://localhost/redirect",
                response_type: "token id_token",
                scope: "openid link ban lol_region",
            }).then((response) => {
                const cookies = response.headers["set-cookie"];
                this.client.put(
                    "xxx",
                    {
                        type: "auth",
                        username: account.username,
                        password: account.password,
                        remember: false,
                        language: "en_GB",
                        region: this.region.login,
                    },
                    {
                        headers: {
                            Cookie: cookies,
                        },
                    }
                ).then(async (response) => {
                    //200 OK
                    const { data } = response;
                    if (data.error) {
                        //Error is present.
                        switch (data.error) {
                            case "auth_failure":
                                resolve({ type: CheckResponseType.INVALID });
                                break;
                            case "rate_limited":
                                reject({ type: CheckResponseType.RATE_LIMITED, proxy: this.proxy });
                                break;
                            default:
                                console.log("Unknown auth response error type: ", data.error)
                                reject({ type: CheckResponseType.RETRY });
                        }
                    } else {
                        //Login was successful - we can now get auth token and check champs etc.
                        const { uri } = data.response.parameters;
                        const access_token = /#access_token=(.*?)&/.exec(uri)[1] || null;
                        this.client.defaults.headers = {
                            Authorization: `Bearer ${access_token}`
                        }
                        this.client.post("xxx").then(async (response) => {
                            const userInfo = response.data;
                            const summoner: Summoner = {
                                account: account,
                                region: this.region,
                                id: userInfo.lol.cuid,
                                profileIcon: userInfo.lol_account.profile_icon,
                                name: userInfo.lol_account.summoner_name,
                                level: userInfo.lol_account.summoner_level,
                                emailVerified: userInfo.email_verified,
                                phoneVerified: userInfo.phone_number_verified
                            }
                            if (userInfo.ban.code) {
                                resolve({ type: CheckResponseType.BANNED });
                            } else {
                                try {
                                    const accountId = userInfo.lol.cuid;
                                    const inventory = await this.client.get(`xxx`);
                                    const champions = inventory.data.data.items.CHAMPION;
                                    const skins = inventory.data.data.items.CHAMPION_SKIN;
                                    const store = await this.client.get(`xxx`);
                                    const matchHistory = await this.client.get(`xxx`);
                                    const lastPlayed = matchHistory.data.games.games[0].gameCreation;
                                    summoner.data = {
                                        blueEssence: store.data.player.ip,
                                        riotPoints: store.data.player.rp,
                                        refunds: store.data.refundCreditsRemaining,
                                        champions: [],
                                        skins: [],
                                        lastPlayed: lastPlayed
                                    }
                                    champions.map((champion) => {
                                        summoner.data.champions.push({
                                            id: champion.itemId,
                                            purchaseDate: champion.purchaseDate
                                        });
                                    });
                                    skins.map((skin) => {
                                        summoner.data.skins.push({
                                            id: skin.itemId,
                                            purchaseDate: skin.purchaseDate,
                                            vintage: skin.payload.isVintage
                                        });
                                    });
                                    resolve({ type: CheckResponseType.SUCCESS, summoner: summoner });
                                } catch {
                                    reject({ type: CheckResponseType.RETRY });
                                }
                            }
                        });
                    }
                }).catch(() => {
                    reject({ type: CheckResponseType.RETRY });
                });
            }).catch(() => {
                reject({ type: CheckResponseType.RETRY });
            });
        });
    }
}

However, if there’s an issue with a proxy, I get unhandled promise rejections like this that seem to be coming from the socket:

(node:2200) UnhandledPromiseRejectionWarning: Error: connect ETIMEDOUT 46.101.212.177:9050
        at SocksClient.closeSocket (C:NodeAppslol-crackernode_modulessocksbuildclientsocksclient.js:364:32)
        at SocksClient.onErrorHandler (C:NodeAppslol-crackernode_modulessocksbuildclientsocksclient.js:337:14)
        at Socket.onError (C:NodeAppslol-crackernode_modulessocksbuildclientsocksclient.js:199:38)
        at Object.onceWrapper (events.js:422:26)
        at Socket.emit (events.js:315:20)
        at emitErrorNT (internal/streams/destroy.js:92:8)
        at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
        at processTicksAndRejections (internal/process/task_queues.js:84:21)
    (node:2200) 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: 2266)
    (node:2200) [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.

However, I’m pretty sure I’ve handled everything. I even have a try/catch block around my await calls.

Answer

As I’m looking at your code this api call this.client.post("https://auth.riotgames.com/userinfo") doesn’t have catch function. By separating each one of your api calls in different functions and returning them, your code becomes much cleaner and finding these errors becomes easier.



Source: stackoverflow