You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

制作Discord机器人遇TypeError:Token为NoneType问题求助

Discord机器人启动报错:TypeError: expected token to be a str, received NoneType instead

作为编程新手,制作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文件里正确读取到机器人令牌。按以下步骤排查:

  1. 检查.env文件的位置和内容

    • .env文件必须和你的app.py放在同一个文件夹里
    • .env文件里的键名要和代码里完全一致,代码里用的是discord_token,所以.env里要写:discord_token=你的机器人令牌字符串,注意不要给令牌加引号,也不要在=前后加空格
  2. 指定load_dotenv的路径(可选)
    如果你的.env文件不在当前工作目录,可以手动指定路径:

    load_dotenv(dotenv_path='./.env')  # 这里填.env的实际路径
    
  3. 验证环境变量是否加载成功
    在print(DISCORD_TOKEN)后面加一行代码,打印所有环境变量,确认discord_token存在:

    print(os.environ.get("discord_token"))
    

    如果还是None,说明.env文件没被正确读取,检查文件路径和拼写。

  4. 代码优化(额外建议)
    你的代码里同时创建了client = discord.Client(intents=intents)和bot = commands.Bot(...),实际上只需要bot就足够了,删掉client的定义,避免不必要的资源占用。

内容的提问来源于stack exchange,提问作者Moulik Bhatia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:47:15