Discord bot throwing NoneType error when starting up

My Discord bot keeps crashing with this error message:

TypeError: expected token to be a str, received NoneType instead

Here’s my bot code:

import discord
import os

permissions = discord.Intents.default()
permissions.typing = False
permissions.presences = False
bot = discord.Client(intents=permissions)

@bot.event
async def on_ready():
    print('Bot is online as {0.user}'.format(bot))

@bot.event
async def on_message(msg):
    if msg.author == bot.user:
        return

    if msg.content.startswith('!greet'):
        await msg.channel.send('Hi there!')

bot.run(os.getenv('BOT_TOKEN'))

I’m pretty new to making Discord bots and I can’t figure out what’s going wrong. The error happens right when I try to start the bot. I’ve checked other similar questions but none of the solutions worked for me. Any ideas on how to fix this?

Your token retrieval is broken. os.getenv('BOT_TOKEN') returns None because the environment variable isn’t set up right. I hit this same issue when I started with Discord bots. You’ve got two options: set the environment variable on your system, or make a .env file in your project folder with BOT_TOKEN=your_actual_token_here. If you go the .env route, install python-dotenv first, then add from dotenv import load_dotenv and load_dotenv() at the top of your script before the os.getenv call. Also double-check you copied the token correctly from Discord Developer Portal - no extra spaces or weird characters.

looks like your BOT_TOKEN ain’t set right. make sure it’s in your env or .env file - os.getenv() is returning None, so discord can’t see the token.

Had this exact problem three months ago with my first bot. Yeah, os.getenv('BOT_TOKEN') is returning None, but check something else too - sometimes the token gets corrupted when you copy-paste from Discord Developer Portal. I had to regenerate the token completely and make sure I didn’t grab any whitespace. Also, if you’re testing locally vs deploying on Heroku, the environment variable setup is different for each. Try printing os.getenv('BOT_TOKEN') right before bot.run() to see what value it’s actually pulling.