sqlite3查询返回ID值异常致Discord机器人channel.send报错
问题说明
我是一名Discord机器人开发者,项目使用SQLite作为机器人存储数据库,通过npm安装sqlite3依赖包后前期运行无异常,近期出现sqlite3自动修改查询返回值的问题,导致功能无法正常使用。
相关业务代码如下:
const ghostChannels = await new Promise((resolve, reject) => client.db.all(`SELECT * FROM "Ghosts"`, (err, rows) => err ? reject(err) : resolve(rows) ) ); ghostChannels.forEach(async (channel) => { const guildchannel = await message.member.guild.channels.cache.get( channel.id ); console.log(channel.id); console.log(guildchannel); const mess = await guildchannel.send(message.member); await mess.delete(); });
代码运行抛出错误:
Uncaught TypeError TypeError: channel.send is not a function
经排查,sqlite3查询返回的id字段值与数据库中实际存储的ID值不一致,导致无法正确获取频道对象,调用send方法时报错。
故障原因
Discord的资源ID(频道、用户、消息、服务器ID)都是18位长度的雪花ID,数值大小超过了JavaScript原生Number类型的安全整数上限(即Number.MAX_SAFE_INTEGER,值为2^53-1)。
sqlite3默认会将INTEGER类型的字段值自动转为JS的Number类型,大整数转换过程中会出现精度丢失,返回的ID值和实际存储值不一致,最终导致channels.cache.get()拿不到对应的频道对象,guildchannel实际为undefined,调用send方法时就会抛出类型错误。
解决方案
- 配置sqlite3连接参数,开启大整数字符串返回
初始化数据库连接后添加配置,让超出安全整数范围的数值直接以字符串形式返回,不会触发精度丢失,返回的ID值和Discord.js内部使用的字符串ID完全匹配:const sqlite3 = require('sqlite3').verbose(); client.db = new sqlite3.Database('./your_bot.db'); // 关键配置:大数字以字符串格式返回 client.db.configure("bigNumberStrings", true); - 调整表结构字段类型
后续建表时,所有存储Discord ID的字段统一使用TEXT类型,不要使用INTEGER类型,从根源上避免sqlite3自动做数值类型转换,存取ID全程使用字符串格式,不会出现精度问题。 - 修复代码逻辑隐患
原代码使用forEach执行异步逻辑不会等待异步任务执行,容易出现时序问题,同时缺少频道存在性判断,建议替换为for...of循环,增加空值校验:for (const channel of ghostChannels) { const guildchannel = message.member.guild.channels.cache.get(channel.id); // 频道已被删除时跳过后续逻辑,避免报错 if (!guildchannel) continue; const mess = await guildchannel.send(message.member); await mess.delete(); }
注意:所有Discord雪花ID在JS环境中必须以字符串格式存储、传递,任何转成Number类型的操作都会导致精度丢失,出现ID匹配失败的问题。
内容的提问来源于stack exchange,提问作者Zitta
相关产品推荐
相关产品推荐

