Discord.js GuildMember#roles appears to sometimes be undefined - javascript

I have a function that accepts a user ID, and should return an array of all role IDs the user has, from all guilds that the bot is a part of.
To achieve this I wrote the following code
async getRoleList(userId) {
const guilds = this.client.guilds.cache.array();
const guildRoles = [];
const proms = guilds.map(async (guild) => {
const member = await guild.members.fetch(userId).catch(() => {});
if (!member) return;
const roleCollection = member.roles.cache;
guildRoles.push(roleCollection.array().map((role) => role.id));
});
await Promise.all(proms);
const res = guildRoles.flat();
res.push(userId);
return res;
}
However, I have noticed that on occasion I get the following error: TypeError: Cannot read property 'cache' of undefined
I am not able to replicate this bug reliably, it just seemingly randomly is thrown in production. From what I can tell of the discord.js docs the roles property of GuildMember always be there, and so I do not understand how the GuildMember exists but has no role manager.

Try updating your discord.js version with npm. This might have been fixed.
https://github.com/discordjs/discord.js/issues/1870

Related

Cannot read properties of undefined (reading 'join') Discord.js

im trying to create my discord music bot, but when i run it. It cannot join my voiceChannel, returning this error: channel_info.channelId.join is not a function. Below, my code:
const Discord = require('discord.js');
const bot = new Discord.Client({ intents: ["GUILDS", "GUILD_MESSAGES"] });
const ytdl = require('ytdl-core');
const streamOptions = { seek: 0, volume: 1 };
const botToken = 'mytoken';
bot.login(botToken);
bot.on('ready', () => {
console.log('to olain');
});
bot.on('message', msg => {
if (msg.author.bot) {
return;
}
if (msg.content.toLowerCase().startsWith(';p')) {
const channel_info = msg.member.guild.voiceStates.cache.find(user => user.id == msg.author.id);
if (channel_info.channelId == null) {
return console.log('Canal não encontrado!');
}
console.log('Canal encontrado');
channel_info.channelId.join().then(connection => {
const stream = ytdl('https://www.youtube.com/watch?v=BxmMGnvvDCo', { filter: 'audioonly' });
const DJ = connection.playStream(stream, streamOptions);
DJ.on('end', end => {
channel_info.channelId.leave();
});
})
.catch(console.error);
}
});
There are several issues in this code. Even if we fix some of these issues, this code will still not work due to differences between discord.js v12 and v13. Let's get started.
Issue #1
This is not one of the core issues causing your code to not work, but it's something useful to consider. You are doing this to get the voice state of the message author:
msg.member.guild.voiceStates.cache.find(user => user.id == msg.author.id);
When you could easily do the exact same thing in a much shorter, less-likely-to-produce-errors way:
msg.member.voice;
Issue #2
Now this is a core issue causing your code to not work. In fact, it is causing the error in your question. You are trying to do:
channel_info.channelId.join();
That does not make sense. You are trying to join a channel ID? channelId is just a String of numbers like so: "719051328038633544". You can't "join" that String of numbers. You want to join the actual channel that the member is in, like so:
channel_info.channel.join();
Issue #3
Based on how you are using a channelId property instead of channelID, I assume you are on discord.js v13. Voice channels do not have a .join() method on v13; in fact, discord.js v13 has no support for joining or playing audio in voice channels. You must install the discord.js/voice package in order to join a voice channel in discord.js v13. This is critical. Even if you fix the above two issues, you must solve this third issue or your code will not work (unless you downgrade to discord.js v12).

How to count all online members using v13?

So I'm currently trying to get all online members in a specific guild and count them. I already tried these methods:
let onlineMembers = (await interaction.guild.members.fetch()).filter(
(member) => !member.user.bot && member.user.presence.status !== "offline"
);
and
let onlineMembers = interaction.guild.members.cache.filter(member => member.presence.status !== "offline").size
I also tried fetching all members first and filter the result like this:
const allMembers = await interaction.guild.members.fetch();
const onlineMembers = allMembers.filter(member => !member.user.bot && member.presence.status !== "offline");
But I'm always getting this exception:
TypeError: Cannot read property 'status' of undefined
So I went looking for a solution and I noticed that I manually have to activate all intents I want my bot to use. I "activated" the needed intents in my index.js like this:
const client = new Client({
intents: [
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MEMBERS,
Intents.FLAGS.GUILD_PRESENCES
],
});
But this didn't fix my problem either.
In the Discord Developer Portal I also enabled both privileged gateway intents:
And who could have guessed...it still doesn't work. It's weird, because for some members it's working but I need it to work for every member.
Does somebody know how to fix this?
Fetching this information changed in V13
This code will generate an Object with the properties online, idle and dnd:
let GUILD_MEMBERS = await client.guilds.cache.get(config.ids.serverID).members.fetch({ withPresences: true })
var onlineMembers = {
online: await GUILD_MEMBERS.filter((online) => online.presence?.status === "online").size,
idle: await GUILD_MEMBERS.filter((online) => online.presence?.status === "idle").size,
dnd: await GUILD_MEMBERS.filter((online) => online.presence?.status === "dnd").size
}
Let me know, if this works for you

I have the TypeError: Cannot read property 'toString' of undefined

I'm making a discord welcomer bot and there's a problem where when someone joins the server it sends this error:
TypeError: Cannot read property 'toString' of undefined
Here is the source code:
module.exports = (client) => {
const channelid = "865471665168580628";
client.on("guildMemberAdd", (member) => {
const serverid = member.guild.id
const guild = client.guilds.cache.get(serverid);
console.log("member");
const ruleschannel = guild.channels.cache.find(channel => channel.name === "rules");
const message = `welcome <#${member.id}> to music and chill! please read the ${member.guild.channels.cache.get(ruleschannel).toString()} before you start chatting.`;
const channel = member.guild.channels.cache.get(channelid);
channel.send(message);
})
}
Can someone please help me?
It means member.guild.channels.cache.get(ruleschannel) is undefined. As ruleschannel is a channel object, and the Collection#get() method needs a snowflake, you need to use its id property.
So member.guild.channels.cache.get(ruleschannel.id) should work.
A better way would be to check if the ruleschannel exists though. Also, you can just simply add rulesChannel inside the backticks and it gets converted to a channel link. Check out the code below:
client.on('guildMemberAdd', (member) => {
// not sure why not just: const { guild } = member
const guild = client.guilds.cache.get(member.guild.id);
const rulesChannel = guild.channels.cache.find((channel) => channel.name === 'rules');
if (!rulesChannel)
return console.log(`Can't find a channel named "rules"`);
const channel = guild.channels.cache.get(channelid);
const message = `Welcome <#${member.id}> to music and chill! Please, read the ${rulesChannel}.`;
channel.send(message);
});

How can I migrate my code to Discord.js v12 from v11?

I upgraded to Discord.js v12, but it broke my existing v11 code. Here are some examples of things that cause errors:
// TypeError: client.users.get is not a function
const user = client.users.get('123456789012345678')
// TypeError: message.guild.roles.find is not a function
const role = message.guild.roles.find(r => r.name === 'Admin')
// TypeError: message.member.addRole is not a function
await message.member.addRole(role)
// TypeError: message.guild.createChannel is not a function
await message.guild.createChannel('welcome')
// TypeError: message.channel.fetchMessages is not a function
const messages = await message.channel.fetchMessages()
const {RichEmbed} = require('discord.js')
// TypeError: RichEmbed is not a constructor
const embed = new RichEmbed()
const connection = await message.channel.join()
// TypeError: connection.playFile is not a function
const dispatcher = connection.playFile('./music.mp3')
How can I migrate my code to Discord.js v12 and fix these errors? Where can I see the breaking changes v12 introduced?
Here are some of the most common breaking changes introduced in Discord.js v12 that people run into.
Managers
Properties such as Client#users and Guild#roles are now managers, instead of the cached Collection of items. To access this collection, use the cache property:
const user = client.users.cache.get('123456789012345678')
const role = message.guild.roles.cache.find(r => r.name === 'Admin')
In addition, methods such as GuildMember#addRole, Guild#createChannel, and TextBasedChannel#fetchMessages have moved to the respective managers:
await message.member.roles.add(role)
await message.guild.channels.create('welcome')
const messages = await message.channel.messages.fetch()
Collection
The Collection class (e.g. client.users.cache, guild.roles.cache, guild.channels.cache) now only accepts functions, not property keys and values, for .find and .findKey:
// v11: collection.find('property', 'value')
collection.find(item => item.property === 'value')
.exists, .deleteAll, .filterArray, .findAll have also been removed:
// v11: collection.exists('property', 'value')
collection.some(item => item.property === 'value')
// v11: collection.deleteAll()
Promise.all(collection.map(item => item.delete()))
// v11: collection.filterArray(fn)
collection.filter(fn).array()
// v11: collection.findAll('property', value')
collection.filter(item => item.property === 'value').array()
.tap now runs a function on the collection instead of every item in the collection:
// v11: collection.tap(item => console.log(item))
collection.each(item => console.log(item))
// New .tap behaviour:
collection.tap(coll => console.log(`${coll.size} items`))
RichEmbed/MessageEmbed
The RichEmbed class has been removed; use the MessageEmbed class instead which is now used for all embeds (instead of just received embeds).
const {MessageEmbed} = require('discord.js')
const embed = new MessageEmbed()
The addBlankField method has also been removed. This method simply added a field with a zero-width space (\u200B) as the name and value, so to add a blank field do this:
embed.addField('\u200B', '\u200B')
Voice
All of the VoiceConnection/VoiceBroadcast#play*** methods have been unified under a single play method:
const dispatcher = connection.play('./music.mp3')
Client#createVoiceBroadcast has been moved to the ClientVoiceManager:
const broadcast = client.voice.createVoiceBroadcast()
Additionally, StreamDispatcher extends Node.js' stream.Writable, so use dispatcher.destroy() instead of dispatcher.end(). The end event has been removed in favour of the native finish event.
Image URLs
Properties such as User#displayAvatarURL and Guild#iconURL are now methods:
const avatar = user.displayAvatarURL()
const icon = mesage.guild.iconURL()
You can also pass an ImageURLOptions to customise things like format and size.
More information
To find out more about the v12 breaking changes, take a look at the updating guide and the changelog. The documentation is also a good resource for finding a particular method/property.

Making a bug report command but kept getting "Type Error: client.fetchUser is not a function" Discord.js

Just like the title says, I want to make a bug report command that will send me the report.
But I kept getting this for some reason:
UnhandledPromiseRejectionWarning: TypeError: client.fetchUser is not a function
Here is my code:
var lockedList = []; //replace the userID stuff here with the ID's of the users you want to blacklist
const pfix = "h."
const arg = message.content.slice(pfix.length).split(/ +/);
const commnd = arg.shift().toLowerCase();
const person = message.author.username;
const userID = message.author.id;
if (commnd === 'bugreport') {
if (userID == lockedList) {
message.channel.send('***You have abused and f##ked this feature before so you\'re in our blacklist***')
} else {
let bug = arg.slice(0).join(' ');
if (!bug) {
message.channel.send('Huh?! What and Where\'s the f##king bug?!')
} else {
client.fetchUser(myID).then((user) => {
user.send(`${person} of ${message.guild.name} (Guild ID: ${message.guild.id}, User ID: ${userID}) reported the bug: ${bug}`);
});
message.reply('**Your bug was reported. If you abuse and f##k this feature, you\'ll be blacklisted and stopped from using this command.**');
};
};
};
Side notes:
This code is inside the client.on('message', async message => {
I have some codes that is just copied from this one, the feedback and suggest command. Just saying this because it might be related to the problem.
Since discord.js v12 the fetchUser() method was removed.
You should instead use client.users.fetch()
client.users.fetch(myID).then((user) => {
user.send(`${person} of ${message.guild.name} (Guild ID: ${message.guild.id}, User ID: ${userID}) reported the bug: ${bug}`);
})

Categories

Resources