How can I capture user input within a loop in my aiogram asyncio telegram bot?

I’m developing a telegram bot using aiogram and asyncio for a math quiz game. The bot runs a series of questions in a loop, but I can’t seem to capture the user’s input after each question.

The handler begins the quiz and enters a loop to present math problems. I need to pause the loop and wait for the user’s response after asking each question to verify if their answer is correct. At the moment, I’m struggling with how to implement this pause for user input.

@router.message(F.text == "Start Quiz")
async def start_quiz(message: Message, state: FSMContext, user_answer = QuizQuestion.answer):
    await state.set_state(QuizQuestion.answer)
    correct_responses = []
    score = 0
    for question_number in range(1, 51):
        number_one = random.randint(1, 15)
        number_two = random.randint(1, 15)
        expected_result = number_one + number_two
        if expected_result not in correct_responses:
            correct_responses.append(expected_result)
        await message.answer(f'Question {question_number}: {number_one} + {number_two} = ?', reply_markup=keyboard.quiz_buttons)
        if int(user_answer) == expected_result:  # Waiting for user input here
            score += 1
            await message.reply(f"Correct! Your score: {score}")
        else:
            score -= 1
            await message.reply(f"Incorrect! Your score: {score}")

@router.message(QuizQuestion.answer)
async def handle_response(message: Message, state: FSMContext):
    await state.update_data(answer=message.text)
    await message.answer(f"You entered: {message.text}")
    user_answer = await state.get_state()

I keep encountering this error: TypeError: int() argument must be a string, a bytes-like object or a real number, not 'State'

Since this is my first bot project, I’m likely missing a fundamental concept. How do I appropriately wait for user input during the loop?

The problem is you’re cramming everything into one handler, which breaks aiogram’s event-driven setup. I hit this exact issue building my first quiz bot last year. You need to split question asking from answer handling. Store your current question data in FSMContext and let a separate handler deal with responses. In start_quiz, just ask the first question and save the expected answer to state. Then handle_response checks the answer, updates score, generates the next question if there’s one, and stores it. Also, that error happens because you’re using await state.get_state() - that returns the state name, not your data. Use await state.get_data() instead. The loop thing you’re trying won’t work since each message spawns its own handler context.

You’re misunderstanding how telegram bots work with asyncio. Each user message triggers its own handler - you can’t use loops to wait for responses like that. You need a state machine instead. Make each question a separate state. Ditch the loop in start_quiz completely - just ask one question, save the expected answer and question number in FSMContext, then exit. In handle_response, check their answer, update the score, bump the question counter, then either ask the next question or end the quiz. I made this exact mistake building a trivia bot. Trying to keep loop state across async handlers never works because each message gets processed independently.

Yeah, you’re mixing synchronous loops with async Telegram handlers - that’s your problem. Each message creates its own context, so the for loop breaks.

Here’s the fix: store question_number and expected_result in state data instead of variables. When the user answers, grab that data with get_data(), check if it’s right, bump up the question number, then either ask the next question or end the quiz.

That error you’re getting? You’re trying to convert a State object to int. You need the actual message text from state data.