11 октября 2026 г.
ImportError: cannot import name 'executor' from 'aiogram.utils' — aiogram 2 и 3
Взяли бота из туториала, с YouTube или из ответа ChatGPT, поставили aiogram — и он падает на первой же строке с ImportError: cannot import name 'executor' from 'aiogram.utils' (или from 'aiogram'). Код не сломан: он написан под aiogram 2, а установился aiogram 3.
Почему так
aiogram 3 вышел несовместимым со второй версией. Когда в requirements.txt написано просто aiogram (или вы сделали pip install aiogram), ставится последняя, третья. А огромная часть примеров в интернете — и многое из того, что пишут нейросети, — до сих пор под вторую. В третьей версии executor нет вообще.
Код под aiogram 2 узнаётся по таким строкам:
from aiogram import executor # или from aiogram.utils import executor executor.start_polling(dp, skip_updates=True) dp = Dispatcher(bot) @dp.message_handler(commands=["start"]) from aiogram.dispatcher import FSMContext from aiogram.contrib.fsm_storage.memory import MemoryStorage
С тем же корнем бывают и другие ошибки: No module named 'aiogram.contrib', cannot import name 'FSMContext' from 'aiogram.dispatcher', AttributeError: 'Dispatcher' object has no attribute 'message_handler'. Лечится всё одинаково.
Вариант А. Поставить aiogram 2 — быстро
Зафиксируйте вторую версию в requirements.txt:
aiogram==2.25.2
Код менять не нужно. Минус: вторая версия больше не развивается, а её зависимости старые. На Python 3.12 и новее она не устанавливается: pip падает на сборке aiohttp (Failed to build installable wheels … (aiohttp)). Так что вариант А годится только там, где Python 3.11 или старше. На botdepo боты собираются на Python 3.12, поэтому здесь — только вариант Б.
Вариант Б. Переписать под aiogram 3
Для простого бота это 10 минут. Было (aiogram 2):
import os
from aiogram import Bot, Dispatcher, executor, types
bot = Bot(token=os.getenv("BOT_TOKEN"))
dp = Dispatcher(bot)
@dp.message_handler(commands=["start"])
async def start(message: types.Message):
await message.answer("Привет!")
@dp.message_handler()
async def echo(message: types.Message):
await message.answer(message.text)
if __name__ == "__main__":
executor.start_polling(dp, skip_updates=True)Стало (aiogram 3):
import asyncio
import os
from aiogram import Bot, Dispatcher, F
from aiogram.filters import CommandStart
from aiogram.types import Message
bot = Bot(token=os.getenv("BOT_TOKEN"))
dp = Dispatcher()
@dp.message(CommandStart())
async def start(message: Message):
await message.answer("Привет!")
@dp.message(F.text)
async def echo(message: Message):
await message.answer(message.text)
async def main():
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())Что поменялось:
Dispatcher()создаётся без бота, бот передаётся вstart_polling(bot).@dp.message_handler(commands=[…])→@dp.message(Command("…"))илиCommandStart()для /start;callback_query_handler→@dp.callback_query(…).- Запуск — через
asyncio.run(main())вместоexecutor. - Состояния:
FSMContextтеперь вaiogram.fsm.context,StateиStatesGroup— вaiogram.fsm.state;MemoryStorageподключать не нужно, он по умолчанию. - Если бот большой, хендлеры удобно разнести по файлам через
Router()и подключить ихdp.include_router(router).
И в requirements.txt напишите aiogram>=3, чтобы дальше не гадать.
Ещё одна ловушка внутри третьей версии
В свежих версиях aiogram 3 убрали parse_mode из конструктора бота. Код вида Bot(token=…, parse_mode="HTML") из чуть более старых примеров падает с TypeError. Теперь так:
from aiogram.client.default import DefaultBotProperties
bot = Bot(token=os.getenv("BOT_TOKEN"), default=DefaultBotProperties(parse_mode="HTML"))Или без всего этого
botdepo при деплое отличает код под aiogram 2 от кода под aiogram 3 и, если requirements.txt нет, сам предлагает правильную строку. А при падении бота подсказывает в логе, что не так. Задеплоить бота. Больше про файл зависимостей — в статье как создать requirements.txt.
Частые вопросы
Какую версию выбрать для нового бота?
Третью. Вторая не развивается, и на новом Python с ней будет всё больше проблем.
Как понять, какая версия у меня стоит?
pip show aiogram — строка Version. Или python -c "import aiogram; print(aiogram.__version__)".
ChatGPT снова пишет код под aiogram 2. Что делать?
Прямо укажите в запросе «aiogram 3.x, Dispatcher без бота, @dp.message, asyncio.run(dp.start_polling(bot))» — тогда пример будет под нужную версию.