1
votes

I'm trying to update this code to work with Discord.js v12. I am encountering an error and I'm kinda stumped on how I could fix this error. I have already updated some of the code to work with Discord.js v12.

TypeError: client.channels.fetch(...).send is not a function

at Client. (/home/runner/Log/index.js:44:40) at Client.emit (events.js:314:20) at Client.EventEmitter.emit (domain.js:483:12) at MessageCreateAction.handle (/home/runner/Log/node_modules/discord.js/src/client/actions/MessageCreate.js:31:14) at Object.module.exports [as MESSAGE_CREATE] (/home/runner/Log/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_CREATE.js:4:32) at WebSocketManager.handlePacket (/home/runner/Log/node_modules/discord.js/src/client/websocket/WebSocketManager.js:384:31) at WebSocketShard.onPacket (/home/runner/Log/node_modules/discord.js/src/client/websocket/WebSocketShard.js:444:22) at WebSocketShard.onMessage (/home/runner/Log/node_modules/discord.js/src/client/websocket/WebSocketShard.js:301:10) at WebSocket.onMessage (/home/runner/Log/node_modules/ws/lib/event-target.js:132:16)

const Discord = require('discord.js');
const client = new Discord.Client();
const { prefix, token, logsChannel } = require('./config.json');

client.once('ready', () => {
    console.log('I am alive!');
});

// Messages log
client.on('message', message => {
    // Function
    function isEmpty(collection) {
        for(var arg in collection) {
            if(collection.hasOwnProperty(arg))
                return false;
        }
        return true;
    }
    // Logs
    if(message.author.bot) return;
    let username = message.author.tag;
    let channel = message.channel.name;
    let server = message.channel.guild;
    var serverAvatarURL = message.guild.iconURL;
    var attachment = (message.attachments).array();
    if(isEmpty(attachment)) {
        var img = "";
    } else {
        var img = attachment[0].url;
    }
    let embed_send = new Discord.MessageEmbed()
        .setAuthor(username, message.author.avatarURL)
        .setColor('23c115')
        .setTitle("Message sent!")
        .setDescription(message.content + " " + img)
        .setImage(img)
        .setFooter("#" + channel)
        .setTimestamp();
    client.channels.fetch(logsChannel).send(embed_send);
});

// Message edit log
client.on("messageUpdate", async(oldMessage, newMessage) => {
    // Function
    function isEmpty(collection) {
        for(var arg in collection) {
            if(collection.hasOwnProperty(arg))
                return false;
        }
        return true;
    }
    // Logs
    if (oldMessage.content === newMessage.content) {
        return;
    }

    var attachment = (oldMessage.attachments).array();
    if(isEmpty(attachment)) {
        var img = "";
    } else {
        var img = attachment[0].url;
    }

    let embed_edit = new Discord.MessageEmbed()
        .setAuthor(oldMessage.author.tag, oldMessage.author.avatarURL)
        .setColor('2615c1')
        .setTitle("Message edited!")
        .addField("Old", oldMessage.content + " " + img, true)
        .addField("New", newMessage.content + " " + img, true)
        .setFooter("#" + oldMessage.channel.name)
        .setTimestamp();
    client.channels.fetch(logsChannel).send(embed_edit);
});

// Message delete log
client.on("messageDelete", async message => {
    // Function
    function isEmpty(collection) {
        for(var arg in collection) {
            if(collection.hasOwnProperty(arg))
                return false;
        }
        return true;
    }
    // Logs
    var attachment = (message.attachments).array();
    if(isEmpty(attachment)) {
        var img = "";
    } else {
        var img = attachment[0].url;
    }

    let embed_delete = new Discord.MessageEmbed()
    .setAuthor(message.author.tag, message.author.avatarURL)
    .setColor('c11515')
    .setTitle("Message deleted!")
    .setDescription(message.content + " " + img)
    .setImage(img)
    .setFooter("#" + message.channel.name)
    .setTimestamp();    
    client.channels.fetch(logsChannel).send(embed_delete);
});

client.login(token);

The Original Code:

const Discord = require('discord.js');
const client = new Discord.Client();
const { prefix, token, logsChannel } = require('./config.json');

client.once('ready', () => {
    console.log('I am alive!');
});

// Messages log
client.on('message', message => {
    // Function
    function isEmpty(collection) {
        for(var arg in collection) {
            if(collection.hasOwnProperty(arg))
                return false;
        }
        return true;
    }
    // Logs
    if(message.author.bot) return;
    let username = message.author.tag;
    let channel = message.channel.name;
    let server = message.channel.guild;
    var serverAvatarURL = message.guild.iconURL;
    var attachment = (message.attachments).array();
    if(isEmpty(attachment)) {
        var img = "";
    } else {
        var img = attachment[0].url;
    }
    let embed_send = new Discord.RichEmbed()
        .setAuthor(username, message.author.avatarURL)
        .setColor('23c115')
        .setTitle("Message sent!")
        .setDescription(message.content + " " + img)
        .setImage(img)
        .setFooter("#" + channel)
        .setTimestamp();
    client.channels.get(logsChannel).send(embed_send);
});

// Message edit log
client.on("messageUpdate", async(oldMessage, newMessage) => {
    // Function
    function isEmpty(collection) {
        for(var arg in collection) {
            if(collection.hasOwnProperty(arg))
                return false;
        }
        return true;
    }
    // Logs
    if (oldMessage.content === newMessage.content) {
        return;
    }

    var attachment = (oldMessage.attachments).array();
    if(isEmpty(attachment)) {
        var img = "";
    } else {
        var img = attachment[0].url;
    }

    let embed_edit = new Discord.RichEmbed()
        .setAuthor(oldMessage.author.tag, oldMessage.author.avatarURL)
        .setColor('2615c1')
        .setTitle("Message edited!")
        .addField("Old", oldMessage.content + " " + img, true)
        .addField("New", newMessage.content + " " + img, true)
        .setFooter("#" + oldMessage.channel.name)
        .setTimestamp();
    client.channels.get(logsChannel).send(embed_edit);
});

// Message delete log
client.on("messageDelete", async message => {
    // Function
    function isEmpty(collection) {
        for(var arg in collection) {
            if(collection.hasOwnProperty(arg))
                return false;
        }
        return true;
    }
    // Logs
    var attachment = (message.attachments).array();
    if(isEmpty(attachment)) {
        var img = "";
    } else {
        var img = attachment[0].url;
    }

    let embed_delete = new Discord.RichEmbed()
    .setAuthor(message.author.tag, message.author.avatarURL)
    .setColor('c11515')
    .setTitle("Message deleted!")
    .setDescription(message.content + " " + img)
    .setImage(img)
    .setFooter("#" + message.channel.name)
    .setTimestamp();    
    client.channels.get(logsChannel).send(embed_delete);
});

client.login(token);
2

2 Answers

0
votes

As NullDev mentioned, .fetch() returns a promise so it needs to be resolved first. You can either use .then() and .catch() methods or async/await.

With .then() .catch():

client.channels
  .fetch(logsChannel)
  .then((ch) => ch.send(embed_send))
  .catch(console.error);

The same with async/await:

try {
  (await client.channels.fetch(logsChannel)).send(embed);
} catch (error) {
  console.log(error);
}

If you've got a function (like isEmpty) that you use in three different handlers, you could move this out and only define once. Although you don't even need this. message.attachments returns a collection of attachments in the message. Collections have a .size accessor property that returns the number of elements in the collection.

Checking if there is an attachment is as easy as checking its size: message.attachments.size > 0.

Collections also have a .first() method that gets the first value in this collection. It means you can get the first attachment's URL like this: message.attachments.first().url.

Another error is that message.author.avatarURL will not work as .avatarURL() is a method, so you should call it. You could probably use displayAvatarURL() instead as it returns the user's default avatar if they don't have any.

You can find below your code with all these changes:

const Discord = require('discord.js');
const client = new Discord.Client();
const { prefix, token, logsChannel } = require('./config.json');

client.once('ready', () => {
  console.log('I am alive!');
});

client.on('message', async (message) => {
  if (message.author.bot) return;
  let username = message.author.tag;
  let channel = message.channel.name;
  let img = message.attachments.size > 0 ? message.attachments.first().url : '';

  let embed = new Discord.MessageEmbed()
    .setAuthor(username, message.author.displayAvatarURL())
    .setColor('23c115')
    .setTitle('Message sent!')
    .setDescription(message.content + ' ' + img)
    .setImage(img)
    .setFooter('#' + channel)
    .setTimestamp();

  try {
    let log = await client.channels.fetch(logsChannel);
    log.send(embed);
  } catch (error) {
    console.log(error);
  }
});

client.on('messageUpdate', async (oldMessage, newMessage) => {
  if (oldMessage.content === newMessage.content) return;

  let img =
    oldMessage.attachments.size > 0 ? oldMessage.attachments.first().url : '';

  let embed = new Discord.MessageEmbed()
    .setAuthor(oldMessage.author.tag, oldMessage.author.displayAvatarURL())
    .setColor('2615c1')
    .setTitle('Message edited!')
    .addField('Old', oldMessage.content + ' ' + img, true)
    .addField('New', newMessage.content + ' ' + img, true)
    .setFooter('#' + oldMessage.channel.name)
    .setTimestamp();

  try {
    let log = await client.channels.fetch(logsChannel);
    log.send(embed);
  } catch (error) {
    console.log(error);
  }
});

client.on('messageDelete', async (message) => {
  let img = message.attachments.size > 0 ? message.attachments.first().url : '';

  let embed = new Discord.MessageEmbed()
    .setAuthor(message.author.tag, message.author.displayAvatarURL())
    .setColor('c11515')
    .setTitle('Message deleted!')
    .setDescription(message.content + ' ' + img)
    .setImage(img)
    .setFooter('#' + message.channel.name)
    .setTimestamp();

  try {
    let log = await client.channels.fetch(logsChannel);
    log.send(embed);
  } catch (error) {
    console.log(error);
  }
});

client.login(token);
0
votes

.fetch() returns a Promise.
Thus, you need to wait for the result with .then().

In your code (assuming logsChannel is an ID):

client.channels
    .fetch(logsChannel)
    .then(fetchedChannel => fetchedChannel.send(embed_delete));

currently, you need to update all of your .fetches