Discord.py - AttributeError: 'NoneType' object has no attribute 'connect'

Viewed 1038

I’m trying to write a simple music bot using discord.py to play music using youtube_dl. I’m having problems with my 'join’ command. When I try to use it on discord it gives this error

Ignoring exception in command join:
Traceback (most recent call last):
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/ext/commands/core.py", line 85, in wrapped
    ret = await coro(*args, **kwargs)
  File "/home/runner/Discord-Bot-2/commands.py", line 44, in join
    await ctx.voice_client.connect(ctx.author.voice_channel)
AttributeError: 'NoneType' object has no attribute 'connect'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/ext/commands/bot.py", line 939, in invoke
    await ctx.command.invoke(ctx)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/ext/commands/core.py", line 863, in invoke
    await injected(*ctx.args, **ctx.kwargs)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/ext/commands/core.py", line 94, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'NoneType' object has no attribute 'connect'

This error happens when I’m in a voice channel. If I’m not, the bot follows the code that I wrote and sent a message in discord “You are not connected to a voice channel”. But when I am in a voice channel it gives the error.

The code for the join command is

  @commands.command()
  async def join(self, ctx):
    if ctx.author.voice is None:
      return await ctx.send("You are not connected to a voice channel")
    
    if ctx.voice_client is not None:
      await ctx.voice_client.disconnect()
    
    await ctx.voice_client.connect(ctx.author.voice_channel)
    await ctx.send(f"Connected to {ctx.author.voice_channel}")

I’m pretty sure that I set up everything correctly, but here’s all the code above the join command where I set up the cog for my commands

import discord
from discord.ext import commands
import youtube_dl
import pafy
import asyncio

class Commands(commands.Cog):
  def __init__(self, client):
    self.client = client
    self.song_queue = {}

  @commands.Cog.listener()
  async def on_ready(self):
    for guild in self.client.guilds:
      self.song_queue[guild.id] = []
    print("Cog 'commands' loaded")
  
  async def check_queue(self, ctx):
    if len(self.song_queue[ctx.guild.id]) > 0:
      ctx.voice_client.stop()
      await self.play_song(ctx, self.song_queue[ctx.guild.id][0])
      self.song_queue[ctx.guild.id].pop(0)

  async def search_song(self, amount, song, get_url=False):
    info = await self.client.loop.run_in_executor(None, lambda: youtube_dl.YoutubeDL({"format": "bestaudio", "quiet" : True}).extract_info(f"ytsearch{amount}:{song}", download=False, ie_key="YoutubeSearch"))
    if len(info["entries"]) == 0: 
      return None

    return [entry["webpage_url"] for entry in info["entries"]] if get_url else info
  
  async def play_song(self, ctx, song):
    url = pafy.new(song).getbestaudio().url
    ctx.voice_client.play(discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(url)), after=lambda error: self.client.loop.create_task(self.check_queue(ctx)))
    ctx.voice_client.source.volume = 0.5
1 Answers

I was using an outdated method (voice_client)

  @commands.command()
  async def join(self, ctx):
    if ctx.author.voice is None:
      return await ctx.send("You are not connected to a voice channel")
    else:
      channel = ctx.author.voice.channel
      await channel.connect()
      await ctx.send(f"Connected to voice channel: '{channel}'")
Related