Ошибки в ботах и как их читать

Ошибки в ботах и как их читать

Latand

Хочешь научиться писать ботов? Проходи и смотри бесплатные уроки на площадке Botfather.Dev


В первую очередь, давайте разделим 3 типа ошибок:

  1. Ошибки в Python - например, когда вы делите на ноль
  2. Ошибки при работе с Telegram Bot API - например, когда вы пытаетесь отправить сообщение ботом несуществующему пользователю
  3. Прочие ошибки, при работе с другими библиотеками.

Когда возникает ошибка в коде, вы ее узнаете (обычно) по красному цвету текста и кучи строк, которые вы не планировали выводить. Мы рассмотрим наиболее часто повторяющиеся ошибки. Но, возможно вашей ошибки тут не будет.

Сначала мы научимся читать ошибки, чтобы понимать, что вообще с ними можно делать, а потом разберем типичные ошибки с Python и в Telegram bot API и как их решать.

Содержание статьи

├── Как читать код ошибки?
├── Что писать в чат, если возникла ошибка?
├── Типичные ошибки в Python
├── Типичные ошибки при работе с Telegram Bot API
├── Прочие ошибки

Как читать код ошибки?

Лучше всего это показать на примере. Эту ошибку прислал один из студентов, мы её и разберем. Как обычно, много красного текста, но! Это не должно вас пугать.

Одна из ошибок, которые мне присылают ученики

Самое важное - надо определить, что это таки именно ошибка, а не что-то другое, а это можно сделать по слову Traceback где-то вначале красного текста. Если там такое есть - это ошибка.

Ищем слово Traceback

Тут и начинается код ошибки. Traceback - ("trace", "back") с английского "отследить" и "назад". Т.е. прослеживаем откуда эту ошибка пришла.

Смотрим сверху вниз, сначала в файле (слово File) по пути D:\Python\aiogram-bot-template.... и потом смотрим в конец строки

начало строки
конец строки

Видим в конце

dispatcher.py, line 388, in _process_polling_updates

Это то, откуда эта ошибка появилась позже всего и на чём всё сломалось. Но это не то место, где вы допустили ошибку! Это файл dispatcher.py, который лежит по определенному пути, и в нем на 388 строке, в функции _process_polling_updates (обработка обновлений поллинга) возникла ошибка ошибка в каком-то таком месте:

Все еще сложно понять, что это такое. Вы это не писали? Точно?

Странно... Я тоже этого не писал.

А! Там же ниже еще есть код, оказывается тут выполнялся код функции

await self.process_updates(updates, fast)

А внизу есть код ошибки и этой функции!

Смотрим туда. Там пишет, что ошибка в том же dispatcher.py, в котором выполнялся код функции:

await asyncio.gather(*tasks)

Ну это то точно вы писали! Нет? Уверены???

Значит смотрим ниже.

Дальше идет выполнение какой-то функции:

handler_obj.handler(*args, **partial_data)

В строке 117, в функции notify.

Ну, короче вы поняли, смотрим дальше, пока не появится что-то знакомое.

Ищем исток ошибки, где источник находится в файлах, что писали именно вы!

А! нашел!

Папка, где ученик хранит свой проект называется "Проект", в нем есть папка aiogram-bot-template. Похоже на то.

И тут смотрим как обычно на то, где ошибка возникла, где-то в обоих файлах:

menu_handlers

db_commands

Внимательно!

Сначала выполнилась функция navigate на строке 118, потом list_tiker на строке 74, а потом update_userstiker, в которой выполнилась функция:

await user_tiker.create()

Вот оно! Вот это место, где ученик допустил ошибку. Но не похоже на то, что тут что-то сделано не так. Да и внизу есть какой-то код. Но в любом случае, это 100% то место, где ученик допустил ошибку.

Внизу можно прочитать следующее:

Ошибка RuntimeError: cannot reuse already awaited coroutine. Если английский вам не сильно знаком, а с питоном вы еще пытаетесь подружиться, но до асинхронности еще не дошли, то для вас это будет полной белибердой.

Пытаемся решить ошибку...

Для начала, пробуем прочитать ошибку и перевести ее. Очень часто в самой ошибке содержится уже её решение.

Если это не помогло - пробуем копировать ошибку и просто-напросто ГУГЛИТЬ! ДА!

https://stackoverflow.com/questions/51116849/asyncio-await-coroutine-more-than-once-periodic-tasks
Вот например, один из примеров ответа на эту ошибку. Чаще всего ответы вы найдете на stackoverflow практически на все ошибки!

Если там на английском - не страшно, переводите страницу, благо Google Chrome позволяет это делать максимально просто. А еще лучше, сначала попробуйте саму ошибку перевести!

Вопрос

На том посте видим ответ с галочкой:

Ответ

Тут говорится, что возможно человек путает асинхронные функции с корутинами (сопрограммами). В данном примере sample - функция (или ссылка) на асинхронную функцию, а sample() - уже корутина. И, чтобы забрать данные из корутины, и ее выполнить, необходимо сделать сначала await перед ней.

Почитав немного других постов я понял, что загвоздка в том, что корутину можно await-ить только один раз! Сделать await sample можно всего один раз.

Значит можно сделать предположение, что user_tiker, перед которым стоит await уже был ранее await-нут. Но, на этом мои догадки заканчиваются...

Ах да, тут ученику, по этой ошибке подсказали:

А вот тут похоже, что сначала происходит await id_tiker и потом он передается в User_Tiker. Не уверен в чем тут дело, но возможно gino пытается внутри что-то await-ить, а может быть ученик сделал что-то, но не показал, и поэтому мы можем только гадать в чем была проблема, потому что позже он написал:

Говорит, что перезагрузка бот помогла...

Ну, главное, что решил!

Ах да, мы ж тут не конкретную ошибку разбирали, а возможный путь её решения.

Подытожим:

  1. Ищем Traceback
  2. Читаем его и пытаемся найти то последнее место в коде, где ВЫ могли допустить ошибку. То есть в том, что писали именно вы.
  3. В крайнем случае - обращаемся к концу кода и читаем именно Exception или Error.
  4. Гуглим этот Exception/Error и ищем пути решения.
  5. Отслеживаем в других функциях выше, где вы могли допустить ошибку.
  6. Если ничего не находите дельного - пишите в чаты.

Я не нашел решения! Что писать в чат, когда возникла ошибка?

Очень просто. Есть несколько важных моментов:

  1. Пишите вежливо, никто не обязан за вас решать ваши ошибки, но кто-то найдется, чтобы помочь.
  2. Опишите проблему, если можно, в одном сообщении.
  3. Опишите то, что вы пытались сделать, и какие у вас предположения! Никто не любит помогать тем, кто сразу пишет в чат и не гуглит.
  4. Залейте ВЕСЬ Traceback на pastebin.com или dpaste.org
  5. Можете добавить часть вашего кода, где у вас возникает ошибка, берите функции и строки из трейсбека + 10-20 строк по вниз и вверх, чтобы был понятен контекст проблемы.
С этого скриншота нихрена не понятно, что у вас за ошибка, если что

Ошибки в Python

Ошибок в Python может быть очень много и зависит от контекста. Для того, чтобы они не возникали - надо учить питон. Ага, все таки придется...

Почитать о них всех можно тут: https://docs.python.org/3/library/exceptions.html#concrete-exceptions

Те, с которыми часто сталкиваются:

SyntaxError - ошибка при работе с синтаксисом Python

Пожалуй, самая распространенная ошибка... Если бы все начинали не с ботов, а с изучения языка программирования Python, то было бы лучше!

Она возникает, когда вы просто неправильно ввели код. Когда возникает?

  • Опечатались при создании функции/класса. Ввели не

def dunc():, а

defc func():

Или

clas MyClass():, вместо

class MyClass():

  • Не поставили скобочки/двоеточие/знак равно, где нужно. Например, при создании функции:
def a:
    return 1 
  • Не закрыли скобки
Найдите пропущенную скобку.
А вот и ошибка
  • Не поставили кавычки, когда записываете текст в переменную:

BOT_TOKEN = 1223423543:IOFNGVOIWENOGIBWENIOGEWRNGVEW

  • Используете зарезервированные имена функций в питоне
async уже забронировали.

ImportError - ошибка при работе с импортами.

  • Ошибка импорта библиотеки, очень часто при цикличном импорте. То есть, вы в файле a, импортируете функцию из модуля b. При этом, в модуле b у вас что-то импортируется из модуля a. И питон начинать ходить по кругу и импортировать одно из другого (нет).

Сделайте так, чтобы не пришлось из модуля a импортировать что-то в b. Переместите эту функцию в модуль c.

  • А еще бывает такое:

Если вы запускаете код бота, но не из того модуля, где идет запуск поллинга, а где просто обозначены хендлеры. Этот файл не надо запускать.

ModuleNotFoundError - не установлена библиотека.

Да. Не установлена. Установите ее с помощью pip install <имя библиотеки>, но перед этим убедитесь, что вы ввели правильное название ее из pypi. Названия можно глянуть тут: https://pypi.org/project/pip/

  • А еще, может быть просто вы пытаетесь импортировать файл из своего проекта, но он лежит в другой папке

TypeError - ошибка при работе с типами данных.

Это может произойти, когда вы используете неправильные методы для работы с объектами. Например, вы попытались сложить текст с числом.

TypeError: unsupported operand type(s) for +: 'int' and 'str'

Но еще может возникнуть, когда вы работаете с вызовом функций:

  • TypeError: func() takes 1 positional argument but 2 were given

В функцию передаете больше аргументов, чем она ждет.

  • TypeError: func() got multiple values for argument 'a'

Когда вы передаете в функцию несколько значений для одной переменной.

  • TypeError: func() missing 1 required positional argument: 'a'

Когда вы в функцию не передали нужные аргументы, например positional - те, что идут по порядку

  • TypeError: my_func() missing 1 required positional argument "self"

Это довольно частая ошибка, когда вы работаете с классом, который не инициализирован.

Например, есть класс Bot, у него есть метод get_me, вы пытаетесь запустить функцию Bot.get_me(). И, несмотря на то, что класс имеет этот метод, пока вы не выполните функцию __init__, в которой создастся self, у вас будет эта ошибка.

Функция инит выполняется когда вы создаете экземпляр класса. Как-то так: bot = Bot(). Только после этого можно сделать bot.get_me()

  • TypeError: object function can't be used in `await` expression

Похоже, что кто-то забыл, что await-ить можно только асинхронные функции, а не обычные. Либо уберите await, либо сделайте функцию асинхронной, с помощью приставки async: async def my_func(): ...

  • TypeError: "coroutine" object is not subscriptable

Тут ошибка говорит, что мы не можем достать элемент из корутины. Типа если сделать await bot.get_me()["username"]. Вообще, есть порядок выполнения кода, и тут сначала питон пытается достать элемент по ключу username из корутины bot.get_me(), а потом только он сделает await.

В данном случае, нам надо сначала сделать await, потому мы заключим этот фрагмент в скобки:

(await bot.get_me())["username"]

И тогда все выполнится.

Но ошибка заключается в том, что данный тип объекта не позволяет брать элементы таким способом ["element"], или по индексу [2].

RuntimeWarning: coroutine 'my_func' was never awaited

... RuntimeWarning: Enable tracemalloc to get the object allocation traceback

Не совсем ошибка, но все же частая проблема. У вас была корутина my_func (или другое название), к которой вы не прописали await. Скорее всего вы это должны сделать, поэтому вернитесь и await-ните вашу корутину! Сделайте await my_func()

ValueError - ошибка при работе со переданными значениями.

Возникает, когда вы передаете в функцию значение правильного типа, но неправильного значения. Примеры:

  • Переданный символ ":" (двоеточие) используется функцией для разделения значений в CallbackData, поэтому его нельзя использовать в самих значениях. Это может произойти, когда вы работаете с CallbackData Factory
  • Длина callback_data в инлайн кнопках ограничена 64-ю байтами. Бывают такие ошибки:
  • Пытаетесь из текста сделать int
int("paid") не сработает, проверьте, что вы туда суете.

AttributeError - ошибка при работе с атрибутами классов.

Такая ошибка возникает, когда вы пытаетесь вызвать атрибут (переменную класса), которую этот класс не имеет.

Примеры:

  • AttributeError "NoneType" object has no attribute "run_until_complete"

Довольно частая ошибка, когда пытаются сделать dp.loop.run_until_complete, а dp.loop оказывается равен None. Ну и когда этот объект "ничто", у него и не может быть никаких атрибутов. P.S. Никогда не берите loop из объекта dp.

Ошибки при работе с Telegram Bot API

Вообще, частенько, при работе с Бот АПИ, в ошибке указано решение... Но его почему-то не читают.

aiogram.utils.exceptions.TerminatedByOtherGetUpdates

У вас запущено более одного процесса, которые делают запрос getUpdates к телеграму с одного и того же токена бота Т.е. когда в боте запускается функция start_polling несколько раз в разных процессах.

Вы либо не остановили один процесс и запустили код заново, либо закрыли неправильно Pycharm, не останавливая процесс, и потом запустили бота заново. Либо у вас работает бот на сервере, а вы еще и запускаете на локальном компьютере.

Пожалуйста, найдите этот второй процесс и убейте его. Можно просто перезагрузить компьютер. А если не можете найти - смените токен бота и все решится.

aiogram.utils.exceptions.ChatNotFound

Ошибка возникает, если:

  • Вы ввели неверный идентификатор чата (просто неправильное значение передано в аргумент chat_id)
  • Бот не контактировал с пользователем ранее, поэтому он не может ему написать.

aiogram.utils.exceptions.CantParseEntities

В тексте у вас закрался запрещенный символ.

Обычно, если вы используете parse_mode для форматирования текста (HTML или MARKDOWN), то для того, чтобы понять где у вас в тексте жирный шрифт или курсив - используются специальные символы/теги. Примеры:

  • Для HTML жирный шрифт будет <b>жирный</b>. Поэтому, если в тексте будет что-то типа <coroutine>, то телеграм его не распознает и выдаст эту ошибку
  • Для HTML используемые теги надо закрывать, т.е. если вы начали с тегом <b>, то где-то его надо закрыть: </b>
  • Для MARKDOWN жирный шрифт будет *жирный*. Поэтому, если где-то в тексте будет нечётное количество звездочек, т.е. в тексте где-то появилась звездочка, которой вы не хотели текст сделать жирным - будет ошибка.

Ошибку можно решить с помощью функций quote_html или escape_md:

from aiogram.utils.markdown import quote_html
text = quote_html("<booo>")

aiogram.utils.exceptions.BadRequest

Название ошибки ни о чем не говорит. Просто то, что запрос не состоялся. А вот решение написано в описании ошибки. Например:

  • Not enough rights to export chat invite link - У бота недостаточно прав для того, чтобы создать ссылку-приглашение в чат. Скорее всего он не админ, или просто не имеет на это право.

aiogram.utils.exceptions.ValidationError: Token is invalid!

Все просто, как описано в ошибке. Вы ввели неверный токен. Можете проверить это с помощью функции print. Попробуйте print(BOT_TOKEN) если у вас эта переменная так называется, и убедитесь сами.

Как Частенько такое вижу, когда мои студенты не переименовывают файл .env.dist в .env.

АЛЛО! Расширение dist используется для примеров файлов, а не для того, чтобы туда писались переменные! Переименуйте и тогда подтянется уже ваш токен из файла .env.

aiogram.utils.exceptions.RetryAfter

В телеграме есть лимиты. Например, сообщения советуют слать не чаще 1 секунды в один и тот же чат. Делайте иногда задержки в своем коде между отправкой нескольких сообщений:

await asyncio.sleep(1)

Прочие ошибки

Тут довольно специфичные ошибки, на случай, если вы не нашли выше описание нужной.

ERROR: Command errored out with exit status 1:...

Если у вас именно такая ошибка, или похожая как на скрине - у вас не установилась библиотека на Python3.9. Эта версия на Windows еще не отлажена окончательно, поэтому решение тут - удалить Python3.9 и поставить Python3.8

asyncpg.exceptions.InvalidCatalogNameError: database "..." does not exist

Тут библиотека asyncpg сообщает вам, что в вашей базе данных отсутствует база с именем, указанным в кавычках.

sqlite3.OperationalError: near ")": syntax error

Синтаксическая ошибка в вашем SQL-запросе. Проследите строчку, где этот запрос делается и проверьте где вы написали что-то несусветное рядом со скобкой. Либо не рядом со скобкой (в ошибке будет написано в кавычках).

Report Page