制作Discord机器人遇TypeError:Token为NoneType问题求助
作为编程新手,制作Discord机器人时持续遇到以下报错:
Traceback (most recent call last):
File "c:\Users\bhati\Desktop\molectron\app.py", line 107, in
bot.run(DISCORD_TOKEN)
File "C:\Users\bhati\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 860, in run
asyncio.run(runner())
File "C:\Users\bhati\AppData\Local\Programs\Python\Python39\lib\asyncio\runners.py", line 44, in run
return loop.run_until_complete(main)
File "C:\Users\bhati\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 642, in run_until_complete
return future.result()
File "C:\Users\bhati\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 849, in runner
await self.start(token, reconnect=reconnect)
File "C:\Users\bhati\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 777, in start
await self.login(token)
File "C:\Users\bhati\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 609, in login
raise TypeError(f'expected token to be a str, received {token.class.name} instead')
TypeError: expected token to be a str, received NoneType instead
我的代码如下:
import discord from discord.ext import commands,tasks import os from dotenv import load_dotenv import youtube_dl import asyncio load_dotenv() # Get the API token from the .env file. DISCORD_TOKEN = os.getenv("discord_token") print(DISCORD_TOKEN) intents = discord.Intents().all() client = discord.Client(intents=intents) bot = commands.Bot(command_prefix='!',intents=intents) youtube_dl.utils.bug_reports_message = lambda: '' ytdl_format_options = { 'format': 'bestaudio/best', 'restrictfilenames': True, 'noplaylist': True, 'nocheckcertificate': True, 'ignoreerrors': False, 'logtostderr': False, 'quiet': True, 'no_warnings': True, 'default_search': 'auto', 'source_address': '0.0.0.0' # bind to ipv4 since ipv6 addresses cause issues sometimes } ffmpeg_options = { 'options': '-vn' } ytdl = youtube_dl.YoutubeDL(ytdl_format_options) class YTDLSource(discord.PCMVolumeTransformer): def __init__(self, source, *, data, volume=0.5): super().__init__(source, volume) self.data = data self.title = data.get('title') self.url = "" @classmethod async def from_url(cls, url, *, loop=None, stream=False): loop = loop or asyncio.get_event_loop() data = await loop.run_in_executor(None, lambda: ytdl.extract_info(url, download=not stream)) if 'entries' in data: # take first item from a playlist data = data['entries'][0] filename = data['title'] if stream else ytdl.prepare_filename(data) return filename @bot.command(name='join', help='Tells the bot to join the voice channel') async def join(ctx): if not ctx.message.author.voice: await ctx.send("{} is not connected to a voice channel".format(ctx.message.author.name)) return else: channel = ctx.message.author.voice.channel await channel.connect() @bot.command(name='leave', help='To make the bot leave the voice channel') async def leave(ctx): voice_client = ctx.message.guild.voice_client if voice_client.is_connected(): await voice_client.disconnect() else: await ctx.send("The bot is not connected to a voice channel.") @bot.command(name='play_song', help='To play song') async def play(ctx,url): try : server = ctx.message.guild voice_channel = server.voice_client async with ctx.typing(): filename = await YTDLSource.from_url(url, loop=bot.loop) voice_channel.play(discord.FFmpegPCMAudio(executable="ffmpeg.exe", source=filename)) await ctx.send('**Now playing:** {}'.format(filename)) except: await ctx.send("The bot is not connected to a voice channel.") @bot.command(name='pause', help='This command pauses the song') async def pause(ctx): voice_client = ctx.message.guild.voice_client if voice_client.is_playing(): await voice_client.pause() else: await ctx.send("The bot is not playing anything at the moment.") @bot.command(name='resume', help='Resumes the song') async def resume(ctx): voice_client = ctx.message.guild.voice_client if voice_client.is_paused(): await voice_client.resume() else: await ctx.send("The bot was not playing anything before this. Use play_song command") @bot.command(name='stop', help='Stops the song') async def stop(ctx): voice_client = ctx.message.guild.voice_client if voice_client.is_playing(): await voice_client.stop() else: await ctx.send("The bot is not playing anything at the moment.") if __name__ == "__main__" : bot.run(DISCORD_TOKEN)
我已经查阅相关指南和文档,重装了所有模块,但都没解决问题。原本期望机器人能上线并响应命令,但未能实现。
解决方法
这个报错的核心原因是DISCORD_TOKEN变量的值为None,也就是程序没从.env文件里正确读取到机器人令牌。按以下步骤排查:
检查.env文件的位置和内容
- .env文件必须和你的
app.py放在同一个文件夹里 - .env文件里的键名要和代码里完全一致,代码里用的是
discord_token,所以.env里要写:discord_token=你的机器人令牌字符串,注意不要给令牌加引号,也不要在=前后加空格
- .env文件必须和你的
指定load_dotenv的路径(可选)
如果你的.env文件不在当前工作目录,可以手动指定路径:load_dotenv(dotenv_path='./.env') # 这里填.env的实际路径验证环境变量是否加载成功
在print(DISCORD_TOKEN)后面加一行代码,打印所有环境变量,确认discord_token存在:print(os.environ.get("discord_token"))如果还是None,说明.env文件没被正确读取,检查文件路径和拼写。
代码优化(额外建议)
你的代码里同时创建了client = discord.Client(intents=intents)和bot = commands.Bot(...),实际上只需要bot就足够了,删掉client的定义,避免不必要的资源占用。
内容的提问来源于stack exchange,提问作者Moulik Bhatia

