`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:
the error:
and the d.js code leading to this error:
(
guild.shard
is indeed undefined when printed on console)37 Replies
- 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!node v20.4.0
discord.js v14.11.0
are you sure your client is ready at this point in time?
the
ClientReady
event got fired, so yeahmore so, where is this code?
is this in an event?
not really, it's in an express route callback
I'm doing some tests to create an API
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 intentI 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.
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
I was simply referring to the Guild itself
it's true that members are not cached by default
ohh mb, then yeah I guess it should work
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
propertyjust checked, I get the same error with
this.getClient().guilds.cache.get(guildId);
btwjust to confirm, could you log
<Client>.isReady()
right before getting the guild?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:
(the last true value comes from guild.shard === undefined)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?
like, other places where I would call my resolveGuild() method?
I can check that
I was under the impression
resolveGuild
was where you were changing to .guilds.cache.get()
yup you were right, I actually fetch it a bit earlier in the route callback 👀
yeah that'd do it
so the solution would be to actually wait in getClient() until the bot is actually ready?
any suggestion on how to do that?
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?mostly getting guild and user/member data, with some minimal caching
you can definitely do that with just the rest api
but the REST api wouldn't update my cache on events like guild join, member update, etc., would it?
no, but it seemed like you were fetching everytime anyways
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
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
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
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
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
not sure what you mean by that
<Guild>.members.fetch()
for all members once
it's only 1 api calland the WS connection will still keep track of every member joining and leaving the cached guilds?
yeah that could work
since you'd need the GuildMembers intent to do that, yes, you'd be receiving the associated events
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
yes, you'd need to do that yourself
I think I got it all working, thanks a really lot for your help!