Telebot callback handler not interrupting message flow properly

I’m working on a Python Telegram bot with pyTelegramBotAPI. My bot has a main interface with commands like /postal and /profile. When users click /postal, they need to input a postal code to get location data. After showing the results, there’s a “Back to Menu” button that should return them to the start screen.

The issue is that when users click this button, the callback doesn’t properly stop the current message handler loop. The bot stays stuck in the postal code input function instead of going back to the welcome screen.

import telebot
import requests, json
from telebot import types

API_TOKEN = 'YOUR_BOT_TOKEN'
bot = telebot.TeleBot(token=API_TOKEN, parse_mode='HTML')

@bot.message_handler(commands=['start'])
def welcome_handler(message):
  greeting_text = (
    f'Hi {message.from_user.first_name}! Welcome!\n\n'
    'Here are the available options:\n'
    '1. /postal - Check postal code information\n'
    '2. /profile - Generate random profile data\n\n'
    'Choose a command from above or type it manually.'
  )
  bot.send_message(chat_id=message.from_user.id, text=greeting_text)

@bot.message_handler(commands=['postal'])
def postal_handler(message):
    bot.send_message(chat_id=message.from_user.id, text='Great! Let\'s look up a postal code.\n\nPlease enter the postal code using <u><b>numbers only</b></u>, example: <i>12345678</i>')

@bot.message_handler(commands=['postal'])
def handle_postal_input(message):
  try:
    postal_code = int(message.text)
    api_url = f'https://viacep.com.br/ws/{postal_code}/json/'
    response = requests.get(api_url)

    if response.status_code == 200:
      data = json.loads(response.content.decode('utf-8'))
      result_text = 'Here is the postal code information! \n\nCode: {}\nStreet: {}\nDistrict: {}\nCity: {}\nState: {}\nArea Code: {}\n\nEnter another code or return to main menu.'
      keyboard = types.InlineKeyboardMarkup()
      keyboard.add(
        types.InlineKeyboardButton('Back to Menu', callback_data='/bot_main_menu')
      )
      bot.send_chat_action(chat_id=message.from_user.id, action='typing')
      bot.send_message(chat_id=message.from_user.id, text=result_text.format(data['cep'], data['logradouro'], data['bairro'], data['localidade'], data['uf'], data['ddd']), reply_to_message_id=message.message_id, reply_markup=keyboard)
      bot.register_next_step_handler(message, handle_postal_input)

    else:
      bot.send_message(chat_id=message.from_user.id, text='❌ Invalid data. Please provide a valid postal code.', reply_to_message_id=message.message_id)
      bot.register_next_step_handler(message, handle_postal_input)

  except:
    bot.send_message(chat_id=message.from_user.id, text='❌ Invalid data. Please provide a valid postal code.', reply_to_message_id=message.message_id)
    bot.register_next_step_handler(message, handle_postal_input)

@bot.callback_query_handler(func=lambda call: True)
def button_callback(call):
  if call.data == '/bot_main_menu':
     welcome_handler(call)

I tried creating a callback handler to catch the button press and call the welcome function, but it’s not working. The bot should stop the current input loop and show the main menu message when the button is clicked. How can I properly handle this callback interruption in Telebot?

your callback handler gets a call object, but you’re passing it to welcome_handler that expects a message object. either create the welcome message directly in the callback, or use call.message to grab the message object.

Your code has a bigger problem than what others mentioned - you’ve got two handlers using the same @bot.message_handler(commands=['postal']) decorator. Only one will actually run. The second function handle_postal_input shouldn’t have the command decorator at all since it’s supposed to handle postal code input, not the initial command.

Also, those recursive register_next_step_handler calls are gonna cause headaches. Don’t call bot.register_next_step_handler(message, handle_postal_input) after showing results - just let users enter another code naturally or use the button. Right now you’re stacking handlers which makes everything messy to control.

Restructure it so the postal command only triggers the initial prompt. Then use a separate message handler with proper filters to catch postal codes when you actually need them.

The issue is register_next_step_handler keeps waiting for the next message even after you press the callback button. You need to clear this handler when the callback triggers. Here’s how to fix your callback handler:

@bot.callback_query_handler(func=lambda call: True)
def button_callback(call):
    if call.data == '/bot_main_menu':
        bot.clear_step_handler_by_chat_id(chat_id=call.message.chat.id)
        greeting_text = (
            f'Hi {call.from_user.first_name}! Welcome!\n\n'
            'Here are the available options:\n'
            '1. /postal - Check postal code information\n'
            '2. /profile - Generate random profile data\n\n'
            'Choose a command from above or type it manually.'
        )
        bot.send_message(chat_id=call.message.chat.id, text=greeting_text)

clear_step_handler_by_chat_id() removes the pending step handler so the bot stops expecting postal code input.