`Cannot read properties of undefined (reading 'send')` when fetching guild members

Hi! I got some weird error while fetching the members list of my guild. I believe this is a lib bug, but I want to make sure I didn't miss anything on my side My code:
const guild = await this.getClient().guilds.fetch(guildId);
const members = await guild.members.fetch();
const guild = await this.getClient().guilds.fetch(guildId);
const members = await guild.members.fetch();
the error:
[ERROR] TypeError: Cannot read properties of undefined (reading 'send')
at .../node_modules/discord.js/src/managers/GuildMemberManager.js:237:24
at new Promise (<anonymous>)
at GuildMemberManager._fetchMany (.../node_modules/discord.js/src/managers/GuildMemberManager.js:235:12)
at GuildMemberManager.fetch (.../node_modules/discord.js/src/managers/GuildMemberManager.js:207:31)
...
[ERROR] TypeError: Cannot read properties of undefined (reading 'send')
at .../node_modules/discord.js/src/managers/GuildMemberManager.js:237:24
at new Promise (<anonymous>)
at GuildMemberManager._fetchMany (.../node_modules/discord.js/src/managers/GuildMemberManager.js:235:12)
at GuildMemberManager.fetch (.../node_modules/discord.js/src/managers/GuildMemberManager.js:207:31)
...
and the d.js code leading to this error:
this.guild.shard.send({
op: GatewayOpcodes.RequestGuildMembers,
d: {
guild_id: this.guild.id,
presences,
user_ids: users,
query,
nonce,
limit,
},
});
this.guild.shard.send({
op: GatewayOpcodes.RequestGuildMembers,
d: {
guild_id: this.guild.id,
presences,
user_ids: users,
query,
nonce,
limit,
},
});
(guild.shard is indeed undefined when printed on console)
37 Replies
d.js toolkit
d.js toolkit•12mo ago
- What's your exact discord.js npm list discord.js and node node -v version? - Post the full error stack trace, not just the top part! - Show your code! - Explain what exactly your issue is. - Not a discord.js issue? Check out #useful-servers. - Issue solved? Press the button!
Z_runner
Z_runner•12mo ago
node v20.4.0 discord.js v14.11.0
duck
duck•12mo ago
are you sure your client is ready at this point in time?
Z_runner
Z_runner•12mo ago
the ClientReady event got fired, so yeah
duck
duck•12mo ago
more so, where is this code? is this in an event?
Z_runner
Z_runner•12mo ago
not really, it's in an express route callback I'm doing some tests to create an API
duck
duck•12mo ago
then 2 things 1. could you show getClient? 2. is there a reason you're fetching rather than relying on the cache? guilds should be cached by default if you have the Guilds intent
Z_runner
Z_runner•12mo ago
I didn't push 100% of my code yet but you can see most of the relevant parts here https://github.com/ZRunner/Axobot-API-V2/blob/main/src/bot/client.ts getClient() is at line 29, the error at line 134
GitHub
Axobot-API-V2/src/bot/client.ts at main · ZRunner/Axobot-API-V2
The new TypeScript API for my Discord bot. Contribute to ZRunner/Axobot-API-V2 development by creating an account on GitHub.
Z_runner
Z_runner•12mo ago
and for 2., I'm pretty sure I read somewhere that offline members weren't cached/kept updated, but tell me if I'm wrong there
duck
duck•12mo ago
I was simply referring to the Guild itself it's true that members are not cached by default
Z_runner
Z_runner•12mo ago
ohh mb, then yeah I guess it should work
duck
duck•12mo ago
that being said, are you sure that this if block in getClient isn't what's executing? if it were, then you'd be receiving a client that isn't ready before attempting to fetch a guild, and subsequently receiving a Guild object without its shard property
Z_runner
Z_runner•12mo ago
just checked, I get the same error with this.getClient().guilds.cache.get(guildId); btw
duck
duck•12mo ago
just to confirm, could you log <Client>.isReady() right before getting the guild?
Z_runner
Z_runner•12mo ago
added two things: - console.debug("Client already exists"); in a "else" block in the getClient method - console.debug("client is ready:", this.client && this.client.isReady()); at the beginning of getGuildMemberIds() and the console output:
[16/07/2023 23:30:17] [DEBUG] client is ready: true
[16/07/2023 23:30:17] [DEBUG] Client already exists
[16/07/2023 23:30:17] [DEBUG] true
[16/07/2023 23:30:17] [DEBUG] client is ready: true
[16/07/2023 23:30:17] [DEBUG] Client already exists
[16/07/2023 23:30:17] [DEBUG] true
(the last true value comes from guild.shard === undefined)
duck
duck•12mo ago
I'm unable to reproduce this behavior without attempting to fetch a guild before the client is ready is it possible this isn't the only place you're attempting to fetch guilds?
Z_runner
Z_runner•12mo ago
like, other places where I would call my resolveGuild() method? I can check that
duck
duck•12mo ago
I was under the impression resolveGuild was where you were changing to .guilds.cache.get()
Z_runner
Z_runner•12mo ago
yup you were right, I actually fetch it a bit earlier in the route callback 👀
duck
duck•12mo ago
yeah that'd do it
Z_runner
Z_runner•12mo ago
so the solution would be to actually wait in getClient() until the bot is actually ready? any suggestion on how to do that?
duck
duck•12mo ago
that's one way, yes tbh I'm not entirely sure the full extent of what you want to be able to do, so it's entirely possible you'd be better off just using the rest api with @discordjs/rest but just to answer this, you're always free to make getClient async and await login what exactly do you need the gateway for?
Z_runner
Z_runner•12mo ago
mostly getting guild and user/member data, with some minimal caching
duck
duck•12mo ago
you can definitely do that with just the rest api
Z_runner
Z_runner•12mo ago
but the REST api wouldn't update my cache on events like guild join, member update, etc., would it?
duck
duck•12mo ago
no, but it seemed like you were fetching everytime anyways
Z_runner
Z_runner•12mo ago
lol true but eh, I'd like to actually avoid fetching, I don't know why I decided to fetch the guild tbh https://github.com/ZRunner/Axobot-API-V2/blob/490012e7f3de72991940a49f2989fd1bac47d822/src/bot/client.ts#L88-L90 that should be better, at least for the useless-fetching part now if you have an idea about returning the full list of member IDs without fetching them all each time, I'd be glad to hear it ^^ I wonder if discord has an endpoint for that - probably not tbh yeah no, that would be stupid, sorry. They already have an endpoint to fetch members, why bother with only a subset result feels like my brain isn't working properly at 11:50pm, I should probably go to sleep and try again tomorrow
duck
duck•12mo ago
all means for requesting large amounts of members will have restrictions for a variety of reasons I think the solution for what you want to do depends heavily on what exactly you need all these members for if it's "nothing in particular, I just want to make them available through my api" you should consider not doing that instead
Z_runner
Z_runner•12mo ago
my current use case is for a kind of leaderboard I have in my database a large leaderboard table containing one row for each "participant", but guilds are all mixed in there and I need to return the list of participants in a specific guild so my idea was to get the member IDs, pass it into my SQL query to filter the table, and boom everything works fine until it didn't one other way would be to store in another table in which guilds each participant is, but... I'm not sure if that's actually smarter lol to be extra clear, I have 2 instances of my bot running. One is the regular bot with commands and all, the second is this API
duck
duck•12mo ago
it'd be far easier to just handle participants that you already have data for in your database you probably will want to rely on the member cache then you should only need to fetch members once, then let events handle the cache from there this is assuming you intend to continue using discord.js rather than just the rest api
Z_runner
Z_runner•12mo ago
yeah but my table contains a few thousands of people, wouldn't that mean making thousands of requests at once? even with a pagination system that'd still be a lot I've just checked, I have 29,127 rows rn
duck
duck•12mo ago
not sure what you mean by that <Guild>.members.fetch() for all members once it's only 1 api call
Z_runner
Z_runner•12mo ago
and the WS connection will still keep track of every member joining and leaving the cached guilds? yeah that could work
duck
duck•12mo ago
since you'd need the GuildMembers intent to do that, yes, you'd be receiving the associated events
Z_runner
Z_runner•12mo ago
and I would have to keep track somewhere of which guilds members list were fetched, I don't think d.js can handle that, right? it's probably my best option for sure I mean, this + making getClient() async
duck
duck•12mo ago
yes, you'd need to do that yourself
Z_runner
Z_runner•12mo ago
I think I got it all working, thanks a really lot for your help!