botdepobotdepoВсе статьи

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())

Что поменялось:

  1. Dispatcher() создаётся без бота, бот передаётся в start_polling(bot).
  2. @dp.message_handler(commands=[…]) → @dp.message(Command("…")) или CommandStart() для /start; callback_query_handler → @dp.callback_query(…).
  3. Запуск — через asyncio.run(main()) вместо executor.
  4. Состояния: FSMContext теперь в aiogram.fsm.context, State и StatesGroup — в aiogram.fsm.state; MemoryStorage подключать не нужно, он по умолчанию.
  5. Если бот большой, хендлеры удобно разнести по файлам через 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))» — тогда пример будет под нужную версию.