Discord.js v12向指定频道发消息报错Cannot read property 'send' of undefined
问题原因分析
- 核心错误是
gchannel变量为undefined,导致调用send方法失败,常见诱因有三个:- 模块加载时序问题:你从
index.js引入的client在当前模块执行时还没有完成Discord网关登录,频道缓存还未初始化完成,就算ID正确也无法从缓存中匹配到频道 - 权限缺失:你的Discord机器人没有被授予目标ID频道的「查看频道」「发送消息」「嵌入链接」权限,Discord.js会自动过滤无权限的频道,缓存中不会返回对应对象
- 频道ID填写错误:你填写的频道ID与实际服务器内的频道ID不一致
- 模块加载时序问题:你从
- 额外异常问题:你代码中的所有fetch请求都没有添加catch捕获错误,一旦Mojang API请求失败就会抛出未处理的Promise拒绝,就是你日志里的第二个警告
修复方案
修改后代码如下,补充了登录状态校验、频道存在性判断、异常捕获逻辑,同时优化了冗余的正则替换规则,适配discord.js v13+的embed发送规范:
const Discord = require('discord.js'); const config = require('../config.json'); const { client } = require('../index.js'); const fetch = require('node-fetch'); module.exports = async (bot, jsonMsg, position) => { // 校验client是否已完成登录 if (!client.isReady()) return; // 获取频道后直接做非空校验,不存在直接终止执行 const gchannel = client.channels.cache.get('817842919561232445'); if (!gchannel) return console.log('未找到目标频道,请检查ID、机器人权限及client登录状态'); try { const mojangRes = await fetch(`https://api.mojang.com/users/profiles/minecraft/${(jsonMsg.extra && jsonMsg.text == 'Guild > ' && (jsonMsg.extra[1].text == 'left.' || jsonMsg.extra[1].text == 'joined.')) ? jsonMsg.extra[0].text.replace(/[ ]/g, '') : "steve"}`); const data = await mojangRes.json(); let uuid = data.id ? data.id : "8667ba71b85a4004af54457a9734eed7" // 上下线通知embed const joinEmbed = new Discord.MessageEmbed() .setColor(config.GREEN) .setAuthor(`${jsonMsg.extra ? jsonMsg.extra[0].text : ''} 现已上线`, `https://crafatar.com/avatars/${uuid}.png`); const leaveEmbed = new Discord.MessageEmbed() .setColor(config.RED) .setAuthor(`${jsonMsg.extra ? jsonMsg.extra[0].text : ''} 现已离线`, `https://crafatar.com/avatars/${uuid}.png`); if (jsonMsg.text == 'Guild > ' && jsonMsg.extra[1].text == 'left.') { gchannel.send({ embeds: [leaveEmbed] }); } else if (jsonMsg.text == 'Guild > ' && jsonMsg.extra[1].text == 'joined.') { gchannel.send({ embeds: [joinEmbed] }); } if (jsonMsg.extra) { if (jsonMsg.text == '' && jsonMsg.extra[0].text.startsWith('§2Guild > ')) { // 简化了冗余的颜色代码和身份组替换逻辑 let username = jsonMsg.extra ? jsonMsg.extra[0].text.replace('§2Guild > ', '').replace(/§[0-9a-fk-or]/g, '').replace(/\[VIP(?:\+)?\]|\[MVP(?:\+{1,2})?\]|\[[PDGDGMBGEXGD]\]/g, '').replace(' :', '') : null; let msg = jsonMsg.extra ? jsonMsg.extra[1].text : null; if (username && msg) { if (msg.toLowerCase() == '!botping') { bot.chat(`/gc Pong! 延迟为 ${bot.player.ping}ms.`); } try { const userRes = await fetch(`https://api.mojang.com/users/profiles/minecraft/${username.replace(/[ ]/g, '')}`); const p = await userRes.json(); const messageEmbed = new Discord.MessageEmbed() .setColor(config.GREEN) .setAuthor(username, `https://crafatar.com/avatars/${p.id}.png`) .setDescription(msg) .setFooter("Phazence Discord to Hypixel bridge bot") .setTimestamp(); gchannel.send({ embeds: [messageEmbed] }); } catch (e) { console.log('获取玩家UUID失败:', e) } } } } } catch (err) { console.log('执行逻辑出错:', err) } }
补充注意事项
- 如果你使用的是discord.js v14及以上版本,
MessageEmbed需要替换为从discord.js导入的EmbedBuilder,相关API也要对应调整 - 提前在Discord服务器的频道权限设置中,确认机器人对应的角色已经拿到目标频道的查看频道、发送消息、嵌入链接权限
- 确认频道ID正确:开启Discord开发者模式后,右键目标频道即可复制正确的ID
内容的提问来源于stack exchange,提问作者Tofaa
相关产品推荐
相关产品推荐

