I'm building a discord.js v13.6.0 music bot and everything is working except this code
const { QueryType } = require('discord-player');
module.exports = {
name: 'play',
aliases: ['p'],
utilisation: '{prefix}play [song name/URL]',
voiceChannel: true,
async execute(client, message, args) {
if (!args[0]) return message.channel.send(`${message.author}, Write the name of the music you want to search. ❌`);
const res = await client.player.search(args.join(' '), {
requestedBy: message.member,
searchEngine: QueryType.AUTO
});
if (!res || !res.tracks.length) return message.channel.send(`${message.author}, No results found! ❌`);
const queue = await client.player.createQueue(message.guild, {
metadata: message.channel
});
try {
if (!queue.connection) await queue.connect(message.member.voice.channel);
} catch {
await client.player.deleteQueue(message.guild.id);
return message.channel.send(`${message.author}, I can't join audio channel. ❌`);
}
await message.channel.send(`Your ${res.playlist ? 'Your Playlist' : 'Your Track'} Loading... 🎧`);
res.playlist ? queue.addTracks(res.tracks) : queue.addTrack(res.tracks[0]);
if (!queue.playing) await queue.play();
},
};
When I use this command, the following error occurs:
Unhandled promise rejection: ReferenceError: player is not defined
I'm new to programming, sorry for any silly mistakes, if you need any info don't hesitate to ask
The possibility of such errors appears either by throwing inside of a async function without a catch block or rejecting a promise which didn't had a .catch()
You might be doing:
you put your code inside an async function in order to use await calls.
The awaited function fails.
The solutions are:
Either use .catch()
await returnsPromise().catch(e => { console.log(e) })
or
2.Use try/ catch block
try {
await returnsPromise()
} catch (error) {
console.log('That did not go well.')
}
Related
quick basic question,
When setting up guildmember.timout with discord.js v13, it gives an example with .then(console.log) and .catch(console.error). Using the example, the code will continue after the .catch.
muteMember
.timeout(time, reason)
.catch((error) => {
return errors(client, message, args, "mute", error, true);
});
muteMember.send ...
At the moment it will run the errors function then continue onto the code after the .catch, for example muteMember.send. What's the best way to have it "stop" after it runs what is inside of the .catch? Thank you in advance
You can make it return a falsy if the error occurs, then check if it is falsy, and return if it is.
let isModified = await muteMember
.timeout(time, reason)
.catch((error) => {
errors(client, message, args, "mute", error, true)
return false;
})
if (!isModified) return;
You can use async-await with try-catch:
async function myFunction()
{
try
{
await muteMember.timeout(time, reason)
// throws an error if it fails -- jumps to the catch block
muteMember.send...
}
catch(error)
{
errorcheck = true
errors(client, message, args, "mute", error, true);
// and whatever other error handling you would like
}
}
The return statement only returns out of the #catch callback. Handle the promise with a #then callback, thats where you want your code to run when its successful.
muteMember
.timeout(time, reason)
.catch((error) => {
//error
errorcheck = true
return errors(client, message, args, "mute", error, true);
})
.then(() => {
//success
})
muteMember.timeout() returns a Promise, so any code that you want to run after the promise resolves you should wrap in a then() block:
muteMember
.timeout(time, reason)
.then((member) => {
// code that depends on successfully timing out a member
muteMember.send....
})
.catch((error) => {
// only runs if there's an error
errorcheck = true
return errors(client, message, args, "mute", error, true);
});
You can also use the more modern and readable async/await syntax:
const myAsyncFunction = async () => {
try {
const member = await muteMember.timeout(time, reason);
// code that depends on successfully timing out a member
muteMember.send....
} catch (error) {
// only runs if there's an error
errorcheck = true
return errors(client, message, args, "mute", error, true);
}
}
I'm trying to write a test for the sad path of this function:
const awaitFirstStreamForPage = async page => {
try {
await page.waitForSelector('[data-stream="true"]', {
timeout: MAX_DELAY_UNTIL_FIRST_STREAM,
})
} catch (e) {
throw new Error(`no stream found for ${MAX_DELAY_UNTIL_FIRST_STREAM}ms`)
}
}
I managed to write a test that passes, but it takes 10 seconds to run because it actually waits for the test to finish.
describe('awaitFirstStreamForPage()', () => {
it('given a page and no active stream appearing: should throw', async () => {
jest.setTimeout(15000)
const browser = await puppeteer.launch({ headless: true })
const page = await getPage(browser)
let error
try {
await awaitFirstStreamForPage(page)
} catch (err) {
error = err
}
const actual = error.message
const expected = 'no stream found for 10000ms'
expect(actual).toEqual(expected)
await browser.close()
jest.setTimeout(5000)
})
})
There is probably a way to solve it using Jest's fake timers, but I couldn't get it to work. Here is my best attempt:
const flushPromises = () => new Promise(res => process.nextTick(res))
describe('awaitFirstStreamForPage()', () => {
it('given a page and no active stream appearing: should throw', async () => {
jest.useFakeTimers()
const browser = await puppeteer.launch({ headless: true })
const page = await getPage(browser)
let error
try {
awaitFirstStreamForPage(page)
jest.advanceTimersByTime(10000)
await flushPromises()
} catch (err) {
error = err
}
const actual = error.message
const expected = 'no stream found for 10000ms'
expect(actual).toEqual(expected)
await browser.close()
jest.useRealTimers()
})
})
which fails and throws with
(node:9697) UnhandledPromiseRejectionWarning: Error: no stream found for 10000ms
Even though I wrapped the failing function in a try/catch. How do you test a function like this using fake timers?
It's impossible to catch a rejection from awaitFirstStreamForPage(page) with try..catch if it's not awaited.
A rejection should be caught but after calling advanceTimersByTime and potentially after flushPromises.
It can be:
const promise = awaitFirstStreamForPage(page);
promise.catch(() => { /* suppress UnhandledPromiseRejectionWarning */ });
jest.advanceTimersByTime(10000)
await flushPromises();
await expect(promise).rejects.toThrow('no stream found for 10000ms');
The problem doesn’t seem to be the use of fake timers: the error you expected is the one being thrown. However, when testing functions that throw errors in Jest, you should wrap the error-throwing code in a function, like this:
expect(()=> {/* code that will throw error */}).toThrow()
More details here: https://jestjs.io/docs/en/expect#tothrowerror
Edit: For an async function, you should use rejects before toThrow; see this example: Can you write async tests that expect toThrow?
I have the following function:
exports.signup = async(req, res) => {
console.log('signup');
const user = new User({
username: req.body.username,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 8)
});
try {
if (await user.save()) {
if (isNonEmptyArray(req.body.roles)) {
// How do I catch this error? can be a role error or db error
const roles = await Role.find({name: { $in: req.body.roles }}).exec()
user.roles = roles.map(role => role._id);
if (await user.save()) {
success(res, 'Registered!');
}
} else {
// How do I catch this error? can be a role error or a db error
const role = await Role.findOne({name: 'user'}).exec();
user.roles = [role._id];
if (await user.save()) {
success(res, 'Registered!');
}
}
}
} catch(error) {
fail(res, {message: 'Database internal error occured.'});
}
};
Is it correct that the catch will trigger for all errors in the block including calls to await Role.find({name: { $in: req.body.roles }}).exec()? How would I catch this error independently? Do I need to add a try and catch within the try and catch statement?
like you said you can use another try-catch block to distinguish which error are you catching.
try {
const role = await Role.findOne({name: 'user'}).exec();
} catch(err) {
console.log(err);
}
Another idea might be to use the promises and catch the error in each .catch segment, for example
var query = Role.findOne({name: 'user'});
query.exec().then(function () {
// handle success
}).catch(function (err) {
// handle error
});
anyway there are some important to feature to keep in mind when using async/await and try-catch block, I'll put here the conclusion of an article and the link to it if you are interested:
conclusion:
We can use try...catch for synchronous code.
We can use try...catch (in combination with async functions) and the .catch() approaches to handle errors for asynchronous code.
When returning a promise within a try block, make sure to await it if you want the try...catch block to catch the error.
Be aware when wrapping errors and rethrowing, that you lose the stack trace with the origin of the error.
font: https://itnext.io/error-handling-with-async-await-in-js-26c3f20bc06a
im creating a discord bot in Glitch.com and i was creating a Warn command, when i finished i try to node him and it works but when I try to warn someone it not warn the user who i selected, so, i go to console log and i fund this error:
"(node:4677) 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(). (rejection id: 4)"
I watch the async and for me it its good, but idk, can you please help me?
const Discord = require("discord.js");
const fs = require("fs");
const ms = require("ms");
let warns = JSON.parse(fs.readFileSync("./warnings.json", "utf8"));
module.exports.run = async (bot, message, args) => {
if(!message.member.hasPermission("MANAGE_MEMBERS")) return message.reply("I cant warn a staff member");
let wUser = message.guild.member(message.mentions.users.first()) || message.guild.members.get(args[0])
if(!wUser) return message.reply("Sir >:( listen plez mention someone no trollies >:(");
if(wUser.hasPermission("MANAGE_MESSAGES")) return message.reply("hey stahp u dont have permision >:(");
let reason = args.join(" ").slice(22);
if(!warns[wUser.id]) warns[wUser.i
] = {
warns: 0
};
warns[wUser.id].warns++;
fs.writeFile("./warnings.json", JSON.stringify(warns), (err) => {
if(err) console.log(err);
});
let warnEmbed = new Discord.RichEmbed()
.setDescription("Warns")
.setAuthor(message.author.name)
.setColor("#ff0000")
.addField("Warned User", wUser.tag)
.addField("Warned in", message.channel)
.addField("Number of Warnings", warns[wUser.id].warns)
.addField("Reason:", reason);
let warnchannel = message.guild.channels.fin('name', "incidents");
if(!warnchannel) return message.reply("Couldn't find channel, if you dont have one create one");
warnchannel.send(warnEmbed);
if(warns[wUser.id].warns == 2) {
let muterole = message.guild.roles.fin('name', "muted");
if(!muterole) return message.reply("You dont have a muterole!, that breaks my heart :(!");
let mutetime = "10m";
await(wUser.addRole(muterole.id));
message.channel.send('${wUser.tag} has been temporaly muted');
setTimeout(function(){
wUser.removeRole(muterole.id)
message.channel.reply('Carlos is da best')
})
}
if(warns[wUser.id].warns == 3) {
message.guild.member(wUser).ban(reason);
message.channel.send('${wUser.tag} has been banned.')
}
}
Well, whats happening is something inside your function is throwing an error. A promise is failing to resolve. To handle promises failing you either follow with .catch(callback) if you are using the .then(callback).catch(callback) style, or you surround with
try{
}
catch(err){
}
if you're using async and await. This should help you figure out what is failing exactly
Been trying to fetch a link/image from an open API from the following guide: https://discordjs.guide/additional-info/rest-api.html#using-node-fetch
but it is not working. I keep getting an undefined response.
Already tried making async functions and so on but not getting any closer.
Also surrounded it by try-catch clausule to debug but not finding the answer.
module.exports = {
name: 'poes',
description: 'Laat een random poes foto zien',
async execute(message, args) {
const fetch = require('node-fetch');
const {body} = await fetch('https://aws.random.cat/meow').then(response => response.json());
message.channel.send(body.file);
},
};
And this is where it is used:
client.on('message', message => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
if (!client.commands.has(command)) return;
try {
client.commands.get(command).execute(message, args);
} catch (error) {
console.error(error);
message.reply('there was an error trying to execute that command!');
}
}
);
Expected result following the Guide should be a random cat image.
The documentation you're using is incorrect in a couple of ways:
const {body} = await fetch('https://aws.random.cat/meow').then(response => response.json())
That line assumes fetch doesn't fail (with a 404, for instance). This is such a common mistake that I've written it up on my anemic little blog. fetch's promise only rejects on network errors, not HTTP errors. You have to check response.ok or response.status.
That the parsed result will have a body property.
It uses then in an async function, which makes very little sense.
But if I go to https://aws.random.cat/meow, I get this JSON:
{"file":"https:\/\/purr.objects-us-east-1.dream.io\/i\/img_20131111_094048.jpg"}
There's no body there, which is why you get undefined for it.
Here's an example fixing all three issues:
const response = await fetch('https://aws.random.cat/meow');
if (!response.ok) {
throw new Error("HTTP status " + response.status);
}
const body = await response.json();
// ^---^---- no { and }, we don't want to destructure
The response from the api is
{
"file": "https://purr.objects-us-east-1.dream.io/i/r958B.jpg"
}
And you are saying it is
{
"body" : {
"file" : ""
}
}
So you need to dump the brackets
const body = await fetch('https://aws.random.cat/meow')
.then(response => response.json());
or you need to look for file instead
const { file } = await fetch('https://aws.random.cat/meow')
.then(response => response.json());
console.log(file)