KaptExecution в Kotlin: что скрывается за ошибкой Gradle

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: почему KaptExecution ломает сборку и как это исправить

Если вы хоть раз сталкивались с ошибкой A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution, то знаете, как это выбивает из колеи. Сборка падает, Gradle выдает красный текст, а в логах — непонятные stacktraces. На Stack Overflow этот вопрос собрал тысячи просмотров, но большинство ответов — просто "попробуй очистить кеш". Мы пойдем дальше.

В этой статье мы не просто дадим готовые решения. Мы заглянем под капот механизма Kapt (Kotlin Annotation Processing Tool) и разберем, что именно происходит, когда Gradle запускает KaptExecution. Вы узнаете, как работает генерация кода, где прячутся типичные ошибки и как их предотвратить. А главное — получите работающие примеры на Kotlin, которые можно сразу применить в своем проекте.

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

Что такое KaptExecution и зачем он нужен

Kapt — это плагин для Kotlin, который позволяет использовать Java-совместимые annotation processors (например, Dagger, Room, Glide, Moshi) в Kotlin-проектах. Когда вы пишете аннотацию @Inject или @Entity, компилятор генерирует дополнительный код (классы, фабрики, DAO).

Внутри Gradle Kapt работает как отдельная задача. Когда вы запускаете сборку, Gradle вызывает KaptExecution — это команда, которая запускает Kotlin-компилятор с включенным processing аннотаций. Если на этом этапе что-то идет не так (например, processor выбросил исключение или закончилась память), вы видите ту самую ошибку.

Как KaptExecution выглядит в Gradle

В файле build.gradle.kts (или build.gradle) Kapt подключается так:

plugins {
    kotlin("kapt") version "1.9.0"
}

dependencies {
    kapt("com.google.dagger:dagger-compiler:2.48")
}

Когда вы запускаете ./gradlew build, Gradle создает дочерний процесс Java/Kotlin, который выполняет KaptExecution. В этот момент загружаются annotation processors, парсятся аннотации и генерируются файлы в папке build/generated/source/kapt.

Основные причины ошибки KaptExecution

Ошибка может быть вызвана разными факторами. Рассмотрим самые частые сценарии.

1. Конфликт версий Kotlin и Kapt

Kapt — часть Kotlin Gradle Plugin. Если версия плагина не совпадает с версией Kotlin, processor может упасть. Например:

// Неправильно
plugins {
    kotlin("jvm") version "1.8.20"
    kotlin("kapt") version "1.9.0" // конфликт
}

Решение: версии должны совпадать.

2. Недостаточно памяти для annotation processing

KaptExecution запускает отдельный процесс JVM. Если вы обрабатываете много аннотаций (например, Room с десятками сущностей), может не хватить heap. В логах вы увидите OutOfMemoryError.

Решение: увеличьте память для Gradle daemon в gradle.properties:

org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=512m
kapt.use.worker.api=false

3. Баги в annotation processor

Иногда сам processor (например, старая версия Dagger или Room) содержит ошибки. Они проявляются только при определенных структурах кода.

Пример: циклическая зависимость в Dagger может вызвать StackOverflowError внутри KaptExecution.

// Пример проблемного кода
@Module
class MyModule {
    @Provides
    fun provideA(b: B): A = A(b)

    @Provides
    fun provideB(a: A): B = B(a) // циклическая зависимость
}

KaptExecution упадет с сообщением Circular dependency detected. Решение — перепроектировать граф зависимостей.

4. Проблемы с кешированием Gradle

Gradle кеширует результаты Kapt. Если вы изменили код или версию processor, но кеш не обновился, KaptExecution может выдать ошибку из-за несоответствия сгенерированных файлов.

Решение: очистить кеш:

./gradlew clean --refresh-dependencies

Как читать stacktrace ошибки KaptExecution

Когда Gradle выводит ошибку, он показывает длинный стек вызовов. Большинство разработчиков пугаются и сразу идут в Google. Но на самом деле ключевая информация находится в первых 10–15 строках.

Пример stacktrace:

A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution
> Caused by: java.lang.IllegalStateException: @Entity annotated class must have a primary key
  at com.example.room.processor.EntityProcessor.process(EntityProcessor.kt:42)
  ... 23 more

Здесь видно, что проблема в Room: одна из сущностей не имеет первичного ключа. Решение — добавить @PrimaryKey.

Пошаговый план диагностики и исправления

Когда вы видите ошибку KaptExecution, не паникуйте. Следуйте этому алгоритму.

Шаг 1. Проверьте версии Kotlin и Kapt

Убедитесь, что kotlin("jvm") и kotlin("kapt") имеют одинаковую версию. Лучше всего задать версию через переменную:

ext.kotlin_version = '1.9.0'

plugins {
    kotlin("jvm") version kotlin_version
    kotlin("kapt") version kotlin_version
}

Шаг 2. Включите подробные логи Kapt

Добавьте в build.gradle.kts:

kapt {
    showProcessorDetails = true
    useBuildCache = false
    arguments {
        arg("kapt.kotlin.generated", "${buildDir}/generated/source/kapt")
    }
}

Это покажет, какой именно processor упал и с какой ошибкой.

Шаг 3. Проверьте совместимость processor

Если используете Room, Dagger или Moshi, проверьте, поддерживает ли их версия вашу версию Kotlin. Например, Room 2.5.x требует Kotlin 1.8+. Совместимость можно найти в документации библиотеки.

Шаг 4. Увеличьте память

Если проект большой, пропишите в gradle.properties:

org.gradle.jvmargs=-Xmx6g
kapt.use.worker.api=true

Флаг kapt.use.worker.api=true включает безопасный режим обработки.

Шаг 5. Изолируйте проблемный модуль

Если проект мультимодульный, попробуйте собрать только один модуль:

<                

Блоги

Рекомендаций по книгам