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.