In version 11.4.2 (latest stable one) I'm fetching a guild (any guild I tried) and I receive only the first level information. Anything that comes in nested objects (channels, members etc.) is an empty collection.
I tried Master branch and this issue seems to be fixed. But it would be nice for the fix to take place on the stable version as well.
To return non-empty collections in regards to any nested object in the a guild object.
This was not a behavior I had encountered in my past projects.
const discord = require('discord.js');
const client = new discord.Client();
client.login('token');
const guild = client.guilds.get('guildid');
console.log(guild);
console.log(guild.channels, guild.members, guild.roles, guild.emojis);
// output
{
members: { }, // empty
channels: { }, // empty
roles: { }, // empty
presences: { }, // empty
deleted: false,
available: true,
id: "449894715294474692",
name: "Guild Name",
icon: null,
splash: null,
region: "eu-central",
memberCount: 3,
large: false,
features: [ ],
applicationID: null,
afkTimeout: 300,
afkChannelID: null,
systemChannelID: "427694145034819594",
verificationLevel: 0,
explicitContentFilter: 0,
mfaLevel: 0,
joinedTimestamp: 1548127935779,
defaultMessageNotifications: "ALL",
ownerID: "871420893962024974",
_rawVoiceStates: { },
emojis: { } // empty
}
{ }
{ }
{ }
{ }
Further details:
Trying to access client properties without the client being logged in results in empty collections.
This also doesn't work on master, you might use a different (valid) approach on your master build.
Edit: To make sure the client is logged in, put your code inside an event callback. If you want it to happen directly when the bot logs in "ready" is the event of choice
For future requests:
If you need help with discord.js installation or usage, please go to the discord.js Discord server instead:
https://discord.gg/bRCvFy9
This issue tracker is only for bug reports and enhancement suggestions.
No I actually used exactly the same approach with both of them, except that I just replaced all the content of the old module in node_modules/discord.js with the new content and then I run yarn/npm install in the folder to install the modules.
But I did exactly the same thing with both of them and I got two different results.
// actual source code - same approach for both 11.4.2 and Master branch
if (client) {
const guildID: string = req.params.guildID;
const guild: Guild | undefined = client.guilds.get(guildID);
if (guild) {
res.send({channels: guild.channels});
} else {
res.send('Guild was undefined');
}
}
Also if I was not logged in, I dont think I would get a result of the guilds at all, would I? Doesnt Discord API require a Bearer or a Bot token as a Authorization header?
I misread a small portion of that, however the solution still persists
Maybe you were lucky enough that this specific guild/the guild list in question is received relatively quickly seeing that you call the login method before execution of your other code.
The guild data seems to not have arrived though, so the deeper collections are not yet populated (as they are initialized as empty collections).
Please try putting your code into an event callback as mentioned earlier (again, "ready" is appropriate if you want the code to execute immediately after the client is fully logged in).
Yep. but I just told you that I've tested this, and multiple times, on the Master branch and it works perfectly with exactly the same code. It doesnt work with 11.4.2 only. Isn't this a clue that it's probably a bug?
The client has fully logged in. And to be sure of that, I tested this multiple times after delays and delays.
Let me rephrase in a clean listed way
I can reproduce neither the behavior of stable nor master, both outputs are equal and what i expected when first seeing your code (hence my first response being a slight miss of the overall situation)
C:\Users\souji\Documents\projects\djs-testing\stable\index2.js:10
console.log(guild.channels, guild.members, guild.roles, guild.emojis);
^
TypeError: Cannot read property 'channels' of undefined
C:\Users\souji\Documents\projects\djs-testing\master\index2.js:10
console.log(guild.channels, guild.members, guild.roles, guild.emojis);
^
TypeError: Cannot read property 'channels' of undefined
Yeah probably because you have not a guild in your bot?
In your case it says that it cannot find the guild at all.
In my case, where I have logged in with a proper bot token and that bot has access to 1-2 channels, It finds the guild, it outputs the information about the guild (name, id, server etc.) but not the rest of the objects.
Your code error says it all, it can't find channels because guild is undefined.
this bot is on 3 guilds, as such your claim is invalid.
it can not find the guild because (as mentioned in the initial answer) at the point of logging the client is not yet logged in, meaning the client collections (example here client.guilds) will not be populated (as they are initialized as empty collection)
Granted I don't know how it works on your end, but the output above is the expected and correct output of the library assuming this exact code.
The provided solution (putting your code into event callbacks) is the correct and expected way of handling code for your bot for all versions of this library.
Ah I see what you did, pardon me.
You tested the first code, which was without callbacks.
You could test it again and make a request after the client has logged in.
In my instance it has logged in, or else it wouldn't provide anything at all.
That is how I do the things in my server
// /src/index.ts
/*
* Web server
*/
// Dependencies
import * as express from "express";
import * as routes from './routes';
import { server } from '../config/server';
import * as client from './services/client';
// Express app
const app = express();
// Client Logging in
client.login().then(client => {
// Routes
app.use(routes);
});
// Start Webserver
const PORT = server.port || 3001;
app.listen(PORT, () => {
console.log(`Server has started on port ${PORT}`);
});
// /src/services/client.ts
import axios from 'axios';
import { server as serverConfig } from '../../config/server';
import * as Discordjs from 'discord.js';
// Discord Client
let client: Discordjs.Client;
// Login to the bot
async function login(): Promise<Discordjs.Client> {
// Request Bot Token
return new Promise<Discordjs.Client>((resolve, reject) => {
axios.get(serverConfig.apiGatewayURL + '/discord/token')
.then(data => {
// Bot Token
const token: string = data.data as unknown as string;
// Instantiate client
client = new Discordjs.Client();
// Login
if (client !== undefined && client instanceof Discordjs.Client) {
client.login(token)
.then(value =>{
resolve(client);
})
.catch(err => {
reject(err);
});
} else {
reject('Client was undefined');
}
})
.catch(err => {
reject(err);
});
});
}
export { login, client };
And this still happens. It's not about the client haven't logged in, or else it just wouldn't find the objects at all like in your case, right?
And again, this works in the Master branch, but not in the Stable version.
Anything that comes in nested objects (channels, members etc.) is an empty collection.
The output you provided shows empty objects, not Collections, that's an important distinction.
Code [...]
That code can and will never produce that output for two reasons:
Since it's not exactly clear how you got that output and that comment seems like you are sending those as-is via express (see the previous comment), I am going to assume you are looking at the json response from express.
Looking at express:
Calling Response#send with an object will internally call Response#json which will just JSON.stringify the resource in the end.
JSON.stringifying a Map will in the very most cases result in {}. (This is what you are seeing)
("very most" because manually adding enumerable properties to it is possible)
It's "working" there because we added toJSON to pretty much everything. (See #1859; Regarding to the toJSON behaviour in general see MDN)
Collections now serialize to an array of flattened values.
Util.flatten internally called from Guild#toJSON and then from Base#toJSON will use a valueOf method if available.
GuildMember, GuildChannel, and GuildEmoji extend Base which defines Base#valueOf returning its id.
That's why your empty objects on 11.4.2 and 11.4-dev are now arrays of ids on master / v12.
Depending on how dynamically you need different objects and their properties:
{ name: guild.name, members: guild.members.keyArray(), etc}@SpaceEEC Thanks thanks thanks!
Very precise, on point and organized answer. It solved all of my problems!
Indeed, the problem was the fact that the objects were serialized.
I replaced this non working code
const categories = guild.channels.filter((channel) => channel.type === 'category');
res.send({categories});
With this code
const categories = guild.channels.filter((channel) => channel.type === 'category');
res.send({categories: categories.keyArray()});
And now it works!
I'm so happy that I understand the problem now and why it works in Master. What a relief :D
But it wasn't a racing problem though, even though the first sample code had a racing problem indeed. Although, I provided it just for sample for my problem, falsly.
Note: I had the same issue of empty client.guilds. My issue was different. It was due to an odd first run of the bot where I suspect I used an older key for a similar bot for the new bot, and invited the wrong bot. It was strange because even after correcting the token and inviting the proper bot I still had the empty guilds on start. I was not able to resolve it until I deleted the bot and remade it.
I'm also encountering this issue trying to create a Discord bot. Following the instructions here, I'm unable to get the list of roles in my Discord server. I'm just trying to output a list of all the users in a role.
const Discord = require('discord.js');
const client = new Discord.Client();
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('message', msg => {
var role = message.guild.roles.get(args[0]);
if (role != null) {
var output = "In role:\n";
output += members.map(member => "<@" + member.user.id + ">");
message.channel.send( output );
} else {
message.channel.send('Invalid role ID ' + args[0] + '.');
}
});
client.login('mytokenhere');
UPDATE: It seems Discord changed the auth token for my bot? I updated my auth token, fixed my code up a little, and now it works.
I stumbled upon a similar thing today; reason is documented in #3924; I was missing the GUILDS intent. This comment is mostly for google searches for "discord.js channels empty" and similar.
Most helpful comment
The output you provided shows empty objects, not Collections, that's an important distinction.
That code can and will never produce that output for two reasons:
The Cause
Since it's not exactly clear how you got that output and that comment seems like you are sending those as-is via express (see the previous comment), I am going to assume you are looking at the json response from express.
Looking at express:
Calling
Response#sendwith an object will internally callResponse#jsonwhich will justJSON.stringifythe resource in the end.JSON.stringifying a Map will in the very most cases result in
{}. (This is what you are seeing)("very most" because manually adding enumerable properties to it is possible)
Why does it work on master / v12 then?
It's "working" there because we added toJSON to pretty much everything. (See #1859; Regarding to the
toJSONbehaviour in general see MDN)Collections now serialize to an array of flattened values.In your Case
Util.flatteninternally called fromGuild#toJSONand then fromBase#toJSONwill use avalueOfmethod if available.GuildMember,GuildChannel, andGuildEmojiextendBasewhich definesBase#valueOfreturning its id.That's why your empty objects on
11.4.2and11.4-devare now arrays of ids onmaster/ v12.A Solution?
Depending on how dynamically you need different objects and their properties:
{ name: guild.name, members: guild.members.keyArray(), etc}