Debugging log · Gradle
"Inconsistent JVM-target compatibility" — when Java and Kotlin disagree
After updating my toolchain, a project that had built fine for months suddenly refused to compile with a message about JVM-target compatibility between compileJava and compileKotlin. Nothing in my code had changed. If you just bumped Android Gradle Plugin, the JDK, or Kotlin and got hit with this, here's what's going on and how to make it stop for good.
The short version: the Java compiler and the Kotlin compiler are targeting different JVM bytecode versions. Pin them both to the same target — ideally with a single Java toolchain — and the error disappears.
The error
Inconsistent JVM-target compatibility detected for tasks 'compileDebugJavaWithJavac' (17) and 'compileDebugKotlin' (11).
The two numbers are JVM bytecode targets. Here Java is compiling to 17 and Kotlin to 11. Gradle now treats that mismatch as an error rather than a warning, because linking bytecode built for two different JVM versions is a recipe for subtle runtime breakage. So instead of guessing, it stops.
Why they drifted apart
They usually start aligned and then one side moves. Common triggers:
- You bumped
sourceCompatibility/targetCompatibility(the Java side) but left the KotlinjvmTargetwhere it was — or vice versa. - A newer Android Gradle Plugin changed the default Java target, while your explicit Kotlin target stayed put.
- You switched the JDK that Gradle runs on, which shifted one compiler's default but not the other's.
The fix is simply to make both compilers agree on one number.
Fix A — the explicit way (both blocks)
Set the Java compatibility and the Kotlin target to the same value in your module's build.gradle:
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions { // older Kotlin plugin
jvmTarget = "17"
}
}
On newer Kotlin plugins kotlinOptions is replaced by a compilerOptions block:
kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
}
}
The exact DSL depends on your Kotlin version, but the principle is unchanged: the Java number and the Kotlin number must match.
Fix B — the clean way (one toolchain)
Better than keeping two numbers in sync is to declare a single Java toolchain and let both compilers inherit it. Then there's only one place to change, and they can't drift again:
kotlin {
jvmToolchain(17)
}
This tells Gradle to compile both Java and Kotlin against JDK 17, downloading it if needed, regardless of which JDK you happen to be running Gradle with. I switched to this and stopped seeing the error entirely — there's simply no second number left to fall out of step.
Rule of thumb: one JVM target, declared once. A toolchain is the single source of truth; two hand-maintained numbers will eventually disagree.
How to confirm it's fixed
- Run a clean build, not just a sync — the error surfaces at compile time.
- If you use a toolchain, remove any leftover
jvmTarget/targetCompatibilityoverrides so nothing quietly contradicts it. - Change one thing at a time. Bumping the JDK, AGP, and Kotlin together makes it impossible to see which knob moved the target.
Version numbers here are illustrative; use whatever target your project actually needs, and keep both compilers on it.