Python 3 Twitch Bot String Encoding Problem

I’m developing a bot for Twitch using Python 3 and I’ve encountered an encoding error. The code was originally written in Python 2, but now I face this issue:

TypeError: a bytes-like object is required, not 'str'

This error occurs when I try to send messages using the socket connection. Below is my implementation:

# utils.py
import config
import urllib3, json
import time, _thread
from time import sleep

def send_message(sock, message):
    sock.send("PRIVMSG #{} :{}\r\n".format(config.CHANNEL, message))

def ban_user(sock, username):
    send_message(sock, ".ban {}".format(username))

def timeout_user(sock, username, seconds=600):
    send_message(sock, ".timeout {} {}".format(username, seconds))

def refresh_moderators():
    while True:
        try:
            url = "http://tmi.twitch.tv/group/user/your_channel/chatters"
            req = urllib3.Request(url, headers={"accept": "*/*"})
            response = urllib3.urlopen(req).read()
            if response.find("502 Bad Gateway") == -1:
                config.moderators.clear()
                data = json.loads(response)
                for mod in data["chatters"]["moderators"]:
                    config.moderators[mod] = "mod"
        except:
            pass
        sleep(5)

def is_moderator(user):
    return user in config.moderators
# bot.py
import config
import utils
import socket
import re
import time, _thread
from time import sleep

def run_bot():
    sock = socket.socket()
    sock.connect((config.HOST, config.PORT))
    sock.send("PASS {}\r\n".format(config.PASSWORD).encode("utf-8"))
    sock.send("NICK {}\r\n".format(config.NICKNAME).encode("utf-8"))
    sock.send("JOIN {}\r\n".format(config.CHANNEL).encode("utf-8"))
    
    MESSAGE_REGEX = re.compile(r"^:\w+!\w+@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :")
    utils.send_message(sock, "Bot has joined the channel!")
    
    _thread.start_new_thread(utils.refresh_moderators, ())
    
    while True:
        data = sock.recv(1024).decode("utf-8")
        if data == "PING :tmi.twitch.tv\r\n":
            sock.send("PONG :tmi.twitch.tv\r\n".encode("utf-8"))
        else:
            user = re.search(r"\w+", data).group(0)
            message = MESSAGE_REGEX.sub("", data)
            
            if message.strip() == "!time":
                utils.send_message(sock, "The current time is: " + time.strftime("%I:%M %p"))
        
        sleep(1)

if __name__ == "__main__":
    run_bot()

I’ve noticed that some lines use .encode("utf-8"), but several do not. What’s the best way to resolve this encoding problem?

yeah, you gotta encode those strings before sending. just put .encode(‘utf-8’) in the send_message function for the message, it’ll sort the type error. mixing str and bytes is the issue.

Had the exact same problem when I moved my IRC bot from Python 2 to 3. Python 3’s socket.send() wants bytes, not strings. You’ve got it right in your main connection code with .encode(‘utf-8’), but your utility functions are missing this. Easiest fix: update your send_message function to handle encoding internally. Then you won’t have to remember it everywhere else. Also, check your urllib3 usage - those method calls don’t look right for the current version. I’d switch to the requests library for HTTP calls instead. It handles encoding way better and the API is cleaner for JSON responses like the Twitch chatters endpoint.

Your problem is inconsistent string encoding. Python 3 socket operations need bytes objects, but your send_message function is passing raw strings. Fix it like this:

def send_message(sock, message):
sock.send(“PRIVMSG #{} :{}\r\n”.format(config.CHANNEL, message).encode(“utf-8”))

Also, your refresh_moderators function has a bug - urllib3.Request and urllib3.urlopen don’t exist. Use urllib.request instead. You’ll hit this encoding issue in other parts of your code too, so make sure all socket sends get encoded to bytes.

Quick fix - wrap your send_message calls with .encode(‘utf-8’) or just modify the function to handle encoding automatically. socket.send() expects bytes in Python 3, that’s why you’re getting the error. Also, that urllib3 code is wrong - should be urllib.request for HTTP stuff.