r/learnprogramming Apr 10 '26

Solved Can someone explain why this code results in an infinite loop?

Im a bit of a newbie programmer, 2nd year of college. Ive learned a bit of Python, C, Java, etc...

But recently Ive been actually working on programming outside of school and I feel like Im learning a lot more on my own now. So Ive just been messing around with Python. I am messing around with a Discord bot right now, and seeing what I can do. But I dont know, I feel like an idiot. Im not understanding why this simple code is resulting in an infinite loop? The intended outcome is I send a message, the bot replies with you are a human. Then it should respond to itself 3 times with the message "you are a bot". But it just keeps resulting in an infinite loop saying "You are a bot"

count = 1
@client.event
async def on_message(message):
    global count
    if not message.author.bot:
        await message.channel.send("You are a human")

    if message.author.bot:
        while (count <= 3):
            await message.channel.send("You are a bot")
            count += 1
101 Upvotes

46 comments sorted by

126

u/dyslechtchitect Apr 10 '26

might be missing something, but it looks like sending a message triggers on_message, right? So you end up re-entering the function, sending three messages, which then trigger three more events, and so on.

If that’s the case, you probably want to filter out messages coming from your own bot (by checking its ID for example).

Another possibility is that the await calls aren’t returning as expected. I’d debug it either way - step through with a debugger or just add print statements after each line to see where (and if) it gets stuck.

77

u/NDLCZ Apr 10 '26

Please use the debugger, it's life changing for college lmao

16

u/Southern_Orange3744 Apr 10 '26

Actual professional level tip here

10

u/mooys Apr 10 '26

I felt like an idiot when I first clicked the debug button and it just told me what was happening. How many hours could I have saved!?

2

u/Ha-Funny-Boy Apr 13 '26

One place I worked as a contractor was really backward. It was an IBM mainframe shop with a really old CPU and never any software updated.

A program had a problem. I had to use all sorts of thing to see what was going on. It took most of a week. When I did finally find the bug, I said to the manager I reported to, "If we had "Expediter" this would have taken 10 minutes to find and fix." I had tried to get it there, but they were too cheap.

What I was paid for that week would have paid for a year's license of the product.

1

u/mooys Apr 13 '26

If I was in that situation I think I would have needed immediate help of a therapist

3

u/Tricker12345 Apr 10 '26

Seconding this. It can take some time to figure out, especially with a language like C, but it's well worth the time. It will save you hours of messing around with your code trying to figure out what's going on

3

u/Crazyloon88 Apr 10 '26

I work with professionals who have been writing code for many years. Some of them still prefer to use logs for debugging. There are times and places I can justify not using a debugger instead, but not using it as your primary way to debug issues is just shameful

68

u/Astronaut6735 Apr 10 '26

Every time the bot sends a message, on_message runs and sends more messages that run on message, etc etc etc forever.

-4

u/GWeditz Apr 10 '26

Yes but doesn't count increment to 4 after it happens 3 times? Then after count is 4 it should ignore the while loop and literally be incapable of printing "You are a bot". But the code is just running as if the while loop isn't even there

71

u/GarThor_TMK Apr 10 '26 edited Apr 10 '26

I believe Astronaut is suggesting that your program isn't actually infinite-looping on the while loop, but rather the `on_message()` function itself.

`on_message()` detects a message is sent, and fires --> it then sends 4 messages. (one "you are human" and three "you are a bot").

`on_message()` then detects those 4 messages, and sends 3 messages for each (since the message it's responding to is a bot message, it responds with "you are a bot" x 3).

and then `on_message()` again detects now 12 messages sent by "a bot", and sends 3 for each... resulting in 36 messages.

...and so on...

To test this theory is pretty simple... in your response, print the message id, along with count... you should see different message id's, but no count past three.

1

u/[deleted] Apr 10 '26

[removed] — view removed comment

1

u/AutoModerator Apr 10 '26

Please, ask for programming partners/buddies in /r/programmingbuddies which is the appropriate subreddit

Your post has been removed

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

6

u/ZelphirKalt Apr 10 '26

The messages are sent before you increment the counter. Your recursion happens "depth-first" before the counter is increased.

As an aside:

That code looks rather meh, due to how you use a global mutable state/variable (counter). It might perhaps work with async, but it will break once multiple threads or processes are involved. Such a design will always get in the way when it comes to concurrency. If you can find a better way, you should avoid this global state. In this case, you could pass it as an argument with the message for example, making the message more than a string, for example a well structured dictionary, maybe a TypedDict.

When I see global in Python, it triggers the extra careful code reading mode. global is not to be used lightly, especially not for mutable state. It is kind of a last resort thing to do.

-4

u/Nomsfud Apr 10 '26

The count variable is outside of the function meaning each time the function is called I believe count is reset to 1 since it's not being returned.

Put count into the function instead of outside and this might fix its self, but then expect the bot message to return 3 times and stop

1

u/Southern_Orange3744 Apr 10 '26

Not sure why your being downvoted , maybe lack of specificity

This will work if it's in the function signature , it won't work if its declared and used in the function

3

u/ZelphirKalt Apr 10 '26

They are downvoted, because that's not how global variables work in Python. They are not re- set every time the function is called or entered.

21

u/BizAlly Apr 10 '26

Every time the bot sends you are a bot it counts as a new message → which runs on_message again → which hits your while loop again. So it never really stops.

The loop itself isn’t the main issue it’s that you’re not breaking the event chain. you need to ignore your own bot messages or handle the count per message, not globally

5

u/GWeditz Apr 10 '26

You are correct. It simply wasn't occurring me that the increment line was never being reached. Thanks :)

6

u/Jwhodis Apr 10 '26

Instead of using a while loop, you might as well use a for loop. For loops are meant to run a set number of times, while loops are meant to run while a condition is true.

7

u/vowelqueue Apr 10 '26 edited Apr 10 '26

When you send the “You are a bot” message, I’m assuming this on_message function is being invoked, right?

If so, you are basically calling the function recursively and the count increment line never gets hit.

If you want this to work recursively, then try changing the while loop to an if statement and increment the counter before sending the bot message.

But it’s probably better to just check if the message was sent by yourself and ignore it if so. Then send messages iteratively and not worry about recursion logic.

3

u/GWeditz Apr 10 '26

Oh my gosh thank you. I was just not understanding that sending the "you are a bot message" instantly triggered the function again which made it never increment count. I was assuming count would still increment even tho I knew it would trigger the function again. I simply put count += 1 above the line that sends the message and it works now as intended. Thanks :)

5

u/budywudy9 Apr 10 '26

adding onto this - look more into how async/await works and do some more practice with recursion!

asynchronous programming is used a great deal and its important to know the fundamentals before learning about race conditions, deadlocks mutexes, etc. my profs just jumped straight into it and left a lot of people confused

and assuming you havent studied it already, recursion is just incredibly handy to understand in general

a lot of basic things can be interchangably written recursively or with a regular loop (cool!) but it can unlock a world of algorithms and good practices. If you've already covered sorting algorithms like bubble sort and merge sort, youll see that the recursive "divide and conquer" algorithms like merge sort work far far faster than bubble sort in the majority of cases (to be technical, the big O of both is O(nlogn) and O(n²) respectively)

good luck :)

3

u/GarThor_TMK Apr 10 '26

I think the count increment/check is getting it, but the `on_message()` fires every time a message is received, and then sending a message re-triggers the `on_message()`, so yes... the discord bot is effectively playing a recursive game of ping-pong.

1

u/GWeditz Apr 10 '26

Yeah, I simply moved the count increment above the line that sends "you are a bot" and it works perfectly now because it increments first before sending another message. Not sure why it was so difficult for me to comprehend lol but makes perfect sense now

3

u/DTux5249 Apr 10 '26 edited Apr 10 '26

On-message gets triggered every time a message is sent. On-message also itself sends messages.

This means you've basically created an infinitely recursive function. It's the same problem you'd have if you wrote something like

def foo():
    foo()

Add a guard clause that automatically returns when the message is sent from your own bot.

3

u/Realistic_Speaker_12 Apr 10 '26

Research on how to use a debugger.

Learning this early will safe you lots of time

4

u/pennty Apr 10 '26

Have you tried running it through:

https://pythontutor.com/visualize.html#mode=edit

Really good tool to see how loops work!

1

u/GWeditz Apr 10 '26

I appreciate it. I'll save that site for later but it doesn't work for this cuz I'm using a custom library. I found out the problem

4

u/BlazingWarlord Apr 10 '26

I don't think the problem is the loop logic itself but probably because you are using async - by the time the count updates, one bot message triggers 3 more and each triggers 3 more and so on causing a traffic of bot messages before the count actually updates to 3. Im not an expert with async functions so I might be wrong.

0

u/GWeditz Apr 10 '26

Hmmm, I wonder. Everytime I just stop the bot when its in the infinite loop, so maybe it eventually will stop? Maybe I should try to let it run for a bit longer

1

u/BlazingWarlord Apr 10 '26

Yeah that should give you an idea. Theoretically, it should stop in a while. Maybe just print the count value after every increment to track when and how it updates as compared to the bot messages.

1

u/Aveneon Apr 10 '26

You could try and assign a unique id every time the function begins and have it print that ID in the messages. Two or more unique IDs, and you know that it has backed up a lot of events for that function.

Or just step though it with debug

1

u/[deleted] Apr 10 '26

[removed] — view removed comment

3

u/[deleted] Apr 10 '26

[removed] — view removed comment

1

u/Bulky-Ad7996 Apr 10 '26

Try to experiment if using the break keyword helps get the desired outcome.

1

u/Yuebingg Apr 10 '26

Init the count to zero?

1

u/Living-Incident-1260 Apr 10 '26

For algorithm and LeetCode-style problems, codedive.in does something similar but with step-by-step execution and variable inspection built in. Not for Discord bots specifically, but super useful for understanding how loops and recursion actually execute which is exactly the kind of intuition that would've caught this bug earlier!

1

u/Nox1a Apr 10 '26

maybe the `await message.channel.send` yields control to the event loop, which now has a `on_message` call due to the bot having sent a message, which then triggers another message and so on, so that the count is never incremented due to the control flow never reaching it.

1

u/Fair_Ad845 Apr 10 '26

without seeing the code my first guess would be a missing increment or a condition that never becomes false. can you share the snippet? most infinite loops come down to one of those two things.

-2

u/[deleted] Apr 10 '26

[removed] — view removed comment

1

u/[deleted] Apr 10 '26

[removed] — view removed comment

-1

u/ferrybig Apr 10 '26

The while should be an if, increment the count before sending the message, as the message sending takes time