Сообщение «произошел сбой в build» с прерыванием сборки чаще всего означает, что один из этапов компиляции или упаковки завершился с ненулевым кодом выхода, и система сборки остановила весь процесс. Конкретную причину показывает не само общее уведомление, а строки лога непосредственно перед ним — именно там находится первичная ошибка: отсутствующая зависимость, синтаксическая ошибка в коде, нехватка памяти или недоступный репозиторий пакетов.
Проблема встречается и при локальной сборке через Gradle, Maven, npm или MSBuild, и в конвейерах CI/CD — GitLab CI, GitHub Actions, Jenkins. Подход к диагностике в обоих случаях одинаков: сначала найти первую ошибку в логе, затем воспроизвести её локально и только после этого менять конфигурацию. Ниже разберём типичные причины прерывания сборки и порядок действий для каждой из них.
Как читать лог сборки и найти первичную ошибку
Главное правило диагностики: первая ошибка в логе — причина, все последующие — следствия. Когда модуль не компилируется, падают зависящие от него задачи, и лог заполняется десятками вторичных сообщений. Прокручивайте вывод вверх до первой строки с маркером ERROR, FAILED или error: — в зависимости от инструмента.
В CI-системах лог разбит по шагам конвейера. Откройте упавший шаг целиком, а не только сводку: сводка обычно содержит лишь финальное «build failed» без деталей. Если лог обрезан интерфейсом, скачайте полный файл лога — такая опция есть в большинстве систем сборки.
Для локальной диагностики полезно повысить детализацию вывода. Например, для Gradle:
./gradlew build --stacktrace --info
Аналогичные флаги подробного вывода есть у большинства сборщиков: --verbose, --debug, -X. Точный флаг смотрите в документации вашего инструмента.
Типичные причины прерывания сборки
На практике сбои build группируются в несколько устойчивых категорий. Определив категорию, вы сужаете круг проверок с «всего подряд» до двух-трёх конкретных действий.
- 🧩 Ошибки в коде или конфигурации — синтаксические ошибки, несовместимые типы, опечатки в файлах сборки (
build.gradle,pom.xml,package.json). - 📦 Проблемы с зависимостями — недоступный репозиторий, удалённая или конфликтующая версия пакета, повреждённый локальный кэш.
- 💾 Нехватка ресурсов — нехватка оперативной памяти (часто проявляется как
OutOfMemoryErrorили внезапное завершение процесса), переполненный диск на агенте сборки. - 🔐 Ошибки доступа — истекшие токены, неверные ключи подписи, отсутствие прав на приватный репозиторий или registry.
- 🌐 Сетевые сбои — таймауты при загрузке зависимостей, недоступность внешних сервисов, блокировка прокси.
- ⚙️ Несовместимость версий инструментов — сборка требует одну версию JDK, Node.js или SDK, а в окружении установлена другая.
Обратите внимание на характер сбоя: стабильно падает на одном и том же шаге — вероятнее ошибка в коде или конфигурации; падает случайным образом — подозревайте сеть, ресурсы или нестабильный агент CI.
Диагностика: пошаговый порядок действий
Действуйте от простого к сложному. Большинство сбоев устраняется на первых трёх шагах, без пересборки окружения.
☑️ Диагностика прерывания сборки
Первый шаг — локальное воспроизведение. Выполните ту же команду сборки на своей машине. Если локально всё собирается, а в CI падает — проблема в окружении агента: версиях инструментов, переменных окружения, кэше или ресурсах. Если падает и локально — причина в коде или зависимостях, и искать её проще.
Второй шаг — очистка кэша. Повреждённый кэш зависимостей — частая причина «внезапных» сбоев, когда сборка вчера работала, а сегодня нет, хотя код не менялся. Для Gradle это удаление каталога ~/.gradle/caches или запуск с флагом --refresh-dependencies; для npm — npm cache clean --force и удаление node_modules. В CI кэш обычно сбрасывается через настройки конвейера.
⚠️ Внимание: очистка кэша безопасна, но следующая сборка займёт заметно больше времени — все зависимости будут загружены заново. Не прерывайте такую сборку по таймауту, если ваш конвейер настроен на короткий лимит времени.
Третий шаг — проверка ресурсов. Убедитесь, что на машине или агенте достаточно свободного места на диске и что процессу сборки выделено достаточно памяти. Для JVM-сборок объём кучи задаётся, например, через org.gradle.jvmargs=-Xmx4g в gradle.properties — подберите значение под объём вашего проекта и возможности машины.
Ошибки зависимостей и сетевые сбои
Если лог показывает ошибки вида Could not resolve, 404 Not Found или таймауты при обращении к репозиторию, проблема на стороне зависимостей или сети. Возможные сценарии: пакет удалён из репозитория, указана несуществующая версия, репозиторий временно недоступен, либо агент сборки находится за прокси, который блокирует загрузку.
Проверьте вручную, открывается ли URL зависимости из лога в браузере или через curl с машины, где падает сборка. Если сборка идёт в CI, помните: сеть агента может отличаться от вашей — проверку нужно выполнять именно в окружении агента, например добавив отладочный шаг в конвейер.
Отдельный случай — конфликт версий, когда разные модули требуют несовместимые версии одной библиотеки. Дерево зависимостей помогает увидеть конфликт: для Gradle это команда ./gradlew dependencies, для Maven — mvn dependency:tree, для npm — npm ls.
Сбои на этапе тестов, подписи и упаковки
Сборка может прерываться не на компиляции, а на поздних этапах. Если падают автотесты, лог покажет конкретный упавший тест — запустите его локально в изоляции. Нестабильные («flaky») тесты, зависящие от времени, сети или порядка выполнения, нередко падают только в CI из-за более медленного окружения.
Ошибки подписи и упаковки (например, при сборке Android APK/AAB или установочных пакетов) обычно связаны с отсутствием keystore-файла, неверным паролем или истёкшим сертификатом. В CI секреты хранятся в переменных окружения — проверьте, что они заданы и не истекли. Точные имена переменных зависят от вашей конфигурации, а не от инструмента сборки.
| Симптом в логе | Вероятная причина | Первое действие |
|---|---|---|
| Compilation error / syntax error | Ошибка в коде или конфиге сборки | Открыть указанный файл и строку, исправить |
| Could not resolve dependency | Недоступен репозиторий или версия пакета | Проверить URL зависимости и версию |
| OutOfMemoryError / процесс завершён | Нехватка памяти сборщику | Увеличить лимит памяти или ресурсы агента |
| Test failed | Падающий или нестабильный тест | Запустить тест локально в изоляции |
| Permission denied / 401 / 403 | Истёк токен, нет прав доступа | Обновить секреты и проверить права |
⚠️ Внимание: не отключайте тесты или проверки качества кода ради «зелёной» сборки без анализа причины. Это маскирует проблему, которая позже проявится уже в готовом продукте.
Когда сборка падает только в CI, но не локально
Расхождение «у меня работает, в конвейере — нет» указывает на различия окружений. Типичные источники расхождения: разные версии JDK, Node.js или SDK; переменные окружения, заданные локально, но отсутствующие в CI; различия в регистре имён файлов (файловая система Linux-агентов чувствительна к регистру, Windows — нет); разный объём памяти и лимиты времени выполнения.
Эффективный приём — воспроизвести сборку в том же контейнере, который использует CI. Если ваш конвейер работает в Docker, запустите сборку локально в том же образе:
docker run --rm -v $(pwd):/app -w /app <образ> <команда сборки>
Так вы увидите ошибку в идентичном окружении и сможете отладить её интерактивно, не отправляя десятки пробных коммитов. Конкретный образ и команду возьмите из конфигурации вашего конвейера.
Почему сборка падает из-за регистра имён файлов
На Windows и macOS (по умолчанию) файловые системы не различают регистр: import из файла «Utils.ts» сработает, даже если файл называется «utils.ts». Linux-агенты CI регистр различают, и такой импорт завершится ошибкой «module not found». Проверьте, что регистр имён в импортах и путях точно совпадает с реальными именами файлов в репозитории.
Профилактика: как снизить число сбоев сборки
Стабильная сборка — результат нескольких практик, а не разового исправления. Фиксируйте версии всех инструментов: версию JDK или Node в конфигурации проекта, версии пакетов в lock-файлах, версию образа CI по тегу, а не по latest. Это делает сборку воспроизводимой и устраняет целый класс «внезапных» сбоев.
Настройте запуск сборки на каждый pull request до слияния в основную ветку — так ошибки ловятся до того, как сломают сборку всем. Полезно также периодически запускать сборку с чистого кэша, чтобы убедиться, что она не зависит от артефактов, оставшихся от старых запусков.
Наконец, держите логи доступными и читаемыми: разбивайте конвейер на небольшие шаги с понятными названиями, включайте информативный вывод сборщика и сохраняйте логи падений. Это сокращает диагностику с часов до минут.
Частые вопросы о сбоях build
Сборка вчера работала, код не менялся, а сегодня сбой. Почему?
Наиболее вероятные причины: изменилась внешняя зависимость (новая или удалённая версия пакета), недоступен репозиторий, истёк токен или сертификат, переполнен диск агента либо повреждён кэш. Начните с очистки кэша и проверки доступности репозиториев.
Что означает «ненулевой код выхода» (exit code 1) в логе?
Это стандартный способ программы сообщить, что она завершилась с ошибкой. Сам по себе код не объясняет причину — смотрите строки лога выше этого сообщения, там находится конкретная ошибка.
Можно ли просто перезапустить сборку в CI?
Да, и это разумный первый шаг при подозрении на сетевой сбой или нестабильный агент. Если после повторного запуска ошибка та же и на том же шаге — причина системная, и перезапуск не поможет, нужна диагностика по логу.
Сборка падает с OutOfMemoryError. Что делать?
Увеличьте лимит памяти для процесса сборки — для JVM-инструментов через параметры вида -Xmx, для Node.js через --max-old-space-size. Если лимит уже велик, проверьте, нет ли утечки в плагинах сборки или слишком тяжёлого шага, который можно разбить на части.
Как понять, что проблема в агенте CI, а не в проекте?
Признаки: сборка стабильно проходит локально и в чистом контейнере, но падает на конкретном агенте; ошибки разные от запуска к запуску; сбои по таймаутам и сети. Попробуйте запуск на другом агенте или в свежем контейнере — если ошибка исчезла, проблема в окружении агента.