Home > database >  Best way to do error handling in a Discord.JS bot?
Best way to do error handling in a Discord.JS bot?

Time:12-11

In my Discord.JS bot, I need to be able to handle all uncaught exceptions.

I understand that I can use process.on('uncaughtException',. . .', but I need the ability to send a message to the channel where the error was triggered (if the error was triggered by a command, of course), and send instructions to report the error (I already have the error reporting method figured out, and I know how to do it without giving them a stack trace or other info - that is not my question).

Of course, I could always just put a try statement in every single part of the code where this is the slightest chance of an error, but this would get very messy. Of course, I could have a module that does the error handling, but what happens if I need to add another argument to the error handler that will require a change in the try statements? I will have to spend hours going through every single file in the bot.

I understand that I will probably need to have some try statements and other error handling methods, but I need to find a more efficient way to do this if possible.

Edit: Yes, I have already tried using a try-catch statement in the command handler. It did nothing. Code:

const {bot} = require('../index');
const { logError } = require("./utils/ErrorHandling.js");

bot.on("interactionCreate", async interaction => {
    if (!interaction.isCommand()) return;

    let cmd = interaction.commandName;

    if (bot.commands.has(cmd)) {
        command = bot.commands.get(cmd);
    } else {
        command = bot.commands.get(bot.aliases.get(cmd));
    }

    try {
        if (command) command.run(bot, interaction); 
    } catch (e) {
        logError(e, interaction.channel);
    }
});

Error handler module:

const { errorLoggingWebhook, supportServer } = require("../config.json")
const fetch = require("node-fetch");

module.exports = {
    "logError": (error, discordChannel) => {
        var errorID = createUUID();

        var params = {
            username: "Aspectfully Error Logging",
            content: `**${errorID}**:

            \`\`\`
            ${error}
            \`\`\``,
        }

        fetch(errorLoggingWebhook, {
            method: "POST",
            headers: {
                'Content-type': 'application/json'
            },
            body: JSON.stringify(params)
        }).then(res => {
            console.log(res);
        }) 

        return discordChannel.send(`An error occured while running that command. 
        
        If this continues to occur, please join our [support server](${supportServer}) and tell them an error is occuring.

        Also, give them the error ID \`${errorID}\`.`)
    }
}

This is an error that occurs. I know there is an easy solution to prevent it from occurring, but I just haven't implemented it yet. This way, I can test the error handling function.

(The error is because I am intentionally trying to process a page from Wikipedia that doesn't exist using the Wikipedia API as if it does exist, therefore trying to read values that don't exist)

C:\Users\bekfe\OneDrive\Documents\Aspectfully\code\commands\wikipedia.js:36
                                wikiParseContents = wikiParse(Object.values(Object.values(JSON.parse(body))[0].text)[0], `https://en.wikipedia.org/wiki/${encodeURI(suffix)}`);
                                                                     ^

TypeError: Cannot convert undefined or null to object
    at Function.values (<anonymous>)
    at C:\Users\bekfe\OneDrive\Documents\Aspectfully\code\commands\wikipedia.js:36:42
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

I am not asking how to solve this specific error. I already know how to solve it. The problem is that the error handler doesn't catch it as an error - my question is about solving this specific error.

I have also tried doing the await function this way, but I have got the same result:

const {bot} = require('../index');
const { logError } = require("../utils/ErrorHandling.js");

bot.on("interactionCreate", async interaction => {
    if (!interaction.isCommand()) return;

    let cmd = interaction.commandName;

    if (bot.commands.has(cmd)) {
        command = bot.commands.get(cmd);
    } else {
        command = bot.commands.get(bot.aliases.get(cmd));
    }

    if (command) {
        try {
            await command.run(bot, interaction); 
        } catch (e) {
            logError(e, interaction.channel);
        }
    }  
});

CodePudding user response:

If command.run is an async function, you need to await it to catch the error

try {
    if (command) await command.run(bot, interaction); 
} catch (e) {
    logError(e, interaction.channel);
}

See how it works here:

async function toThrow() {
 throw new Error("Test")
}
try {
  toThrow() //check your developer console as it doesn't show here
} catch (err) {
  console.log("An error occurred"   err)
}

async function toThrow() {
  throw new Error("Test")
}
(async () => {
try {
  await toThrow()
 } catch (err) {
  console.log("An error occurred: "   err)
}
})()

CodePudding user response:

I ended up adding the unhandled exception listener inside of my interactionCreate like this upon the suggestion of an acquaintance on Discord:

process.on("uncaughtException", (e) => {
    logError(e, interaction.channel)
});

I also realized I forgot to put the createUUID function back in the ErrorHandling.js file, so I added it back (credit):

createUUID = () => {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
       var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
       return v.toString(16);
    });
 }

This really isn't the best solution, but it's what I'm going with for now.

  • Related