Как читать stack trace и находить ошибку
Практика4 минРедакция Innovialabs
Коротко
Stack trace — это цепочка вызовов до места падения: найдите тип и текст ошибки, затем первый фрейм из вашего кода — там почти всегда и нужно чинить.
Что такое stack trace и с чего начинать
Stack trace — это список вызовов функций, которые были активны в момент ошибки. Каждая строка — фрейм: файл, номер строки и имя функции. Читать его нужно в два шага:
- Найдите тип и сообщение ошибки — это ответ на вопрос «что случилось».
- Найдите первый фрейм из вашего кода — это ответ на вопрос «где чинить».
Главная сложность в том, что языки выводят стек в разном порядке. Разберём три примера.
Python: читаем снизу вверх
Traceback (most recent call last):
File "/app/main.py", line 12, in <module>
total = calculate_total(order)
File "/app/billing.py", line 8, in calculate_total
return sum(item["price"] * item["qty"] for item in order["items"])
File "/app/billing.py", line 8, in <genexpr>
return sum(item["price"] * item["qty"] for item in order["items"])
KeyError: 'qty'
- Фраза most recent call last означает: самый свежий вызов — внизу.
- Последняя строка — сама ошибка:
KeyError: 'qty', в словаре нет ключаqty. - Строка над ней — точное место:
billing.py, строка 8. - Выше — путь, которым программа туда пришла:
main.pyвызвалcalculate_total.
Вывод: в одном из товаров заказа нет поля qty. Чинить нужно либо данные, либо функцию (например, item.get("qty", 1), если это допустимо по логике).
Если в трейсе есть фраза During handling of the above exception, another exception occurred, значит, ошибок две: первая — исходная причина, вторая возникла при её обработке. Начинайте с первой.
JavaScript (Node.js): читаем сверху вниз
TypeError: Cannot read properties of undefined (reading 'map')
at renderList (/app/src/list.js:14:22)
at handleRequest (/app/src/server.js:31:10)
at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
- Первая строка — тип и сообщение: у
undefinedпытались вызвать.map. - Сразу под ней — место падения:
list.js, строка 14, колонка 22. - Ниже — кто вызывал. Фреймы из
node_modules— это библиотека (здесь Express), их обычно можно пропустить.
Вывод: в renderList пришёл массив, которого нет. Смотрите, что передаёт handleRequest на строке 31.
В браузере стек может указывать на минифицированный бандл вроде main.3f2a.js:1:48213. Чтобы видеть исходные файлы, включите source maps в сборке и в DevTools.
Java: сверху вниз и обязательно «Caused by»
Exception in thread "main" java.lang.IllegalStateException: Failed to load config
at com.example.App.loadConfig(App.java:42)
at com.example.App.main(App.java:15)
Caused by: java.lang.NumberFormatException: For input string: "abc"
at java.base/java.lang.Integer.parseInt(Integer.java)
at com.example.Config.port(Config.java:27)
at com.example.App.loadConfig(App.java:40)
... 1 more
(Пример упрощён.)
- Верхняя ошибка — «обёртка»: конфиг не загрузился.
- Настоящая причина — в блоке Caused by, и самый нижний такой блок обычно самый важный.
- В нём первый фрейм
java.base— это стандартная библиотека, а первый ваш фрейм —Config.java:27: туда пришла строка"abc"вместо числа. ... 1 moreзначит, что оставшиеся фреймы совпадают с уже показанными выше.
Как найти свой код среди чужих фреймов
- Ищите пути вашего проекта:
/app/src,com.yourcompany, имя репозитория. - Пропускайте
node_modules,site-packages,java.base,org.springframeworkи похожие — ошибка в библиотеке встречается намного реже, чем неверные данные, переданные в неё. - Если ваших фреймов нет совсем, ошибка, скорее всего, в конфигурации или окружении: версии пакетов, переменные окружения, права на файлы.
- Многие IDE подсвечивают фреймы проекта и делают их кликабельными — пользуйтесь этим.
Как эффективно искать ошибку в интернете
- Копируйте тип и сообщение, а не весь трейс:
TypeError: Cannot read properties of undefined. - Убирайте всё уникальное: пути, ID, имена ваших переменных, даты.
- Добавляйте название библиотеки или фреймворка и его мажорную версию.
- Берите точную фразу в кавычки.
- Смотрите issues на GitHub у библиотеки — там часто есть и причина, и обходной путь.
- Если ответ старый, сверяйте его с вашей версией.
Частые ошибки при чтении трейса
- Смотреть только на последнюю строку и игнорировать «Caused by».
- Чинить место падения, а не место, где появились плохие данные.
- Удалять трейс из логов или логировать только
error.messageбез стека. - Глушить исключение пустым
catch/except— стек теряется навсегда.