Skip to main content

Fixing 'Unsupported Class File Major Version' & Gradle 8 Compatibility in Flutter

 You have just upgraded Flutter, Android Studio, or your JDK, and your build pipeline has halted with a stack trace resembling this:

java.lang.IllegalArgumentException: Unsupported class file major version 61

Or perhaps version 65.

This is not a cryptic bytecode error; it is a rigid version mismatch. In the Java ecosystem, class file major versions correspond to specific JDK releases:

  • 61 = Java 17
  • 65 = Java 21

This error occurs when a build tool (specifically Gradle) running on an older JVM attempts to read classes compiled by a newer JDK, or when the Gradle version defined in your project is too old to support the JDK version you are forcing it to run on.

With the release of Android Gradle Plugin (AGP) 8.0, the Android ecosystem has enforced a hard floor of JDK 17. If your Flutter project’s Gradle wrapper or AGP version is outdated, the build fails immediately.

Here is the root cause analysis and the definitive, step-by-step upgrade path to resolve this for modern Flutter applications.

The Root Cause: The Dependency Chain

The breakdown occurs due to a violation of the compatibility matrix between three components:

  1. The Gradle Daemon: The process running the build.
  2. The Android Gradle Plugin (AGP): The logic that builds the APK/AAB.
  3. The Java Development Kit (JDK): The environment compiling the code.

The Breaking Change: Android Gradle Plugin 8.0+ removed support for Java 11. It requires the build to run on Java 17. Consequently, AGP 8.0+ requires Gradle 8.0+.

If you attempt to run Gradle 7.5 (common in older Flutter projects) using JDK 17, Gradle 7 fails because it doesn't fully understand class file version 61. Conversely, if you run Gradle 8 using JDK 11, AGP complains that it needs JDK 17.

The Fix: Aligning the Stack

To fix this, we must align the Gradle Wrapper, the AGP version, and the compiler options to target Java 17 (or 21, if using the absolute latest Gradle).

1. Upgrade the Gradle Wrapper

First, update the distribution URL to a version of Gradle compatible with JDK 17+. Gradle 8.2 or higher is recommended for stability with modern AGP.

File: android/gradle/wrapper/gradle-wrapper.properties

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
# Upgrade to Gradle 8.4 (or latest stable 8.x)
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

2. Update Android Gradle Plugin (AGP) Version

Next, update the root-level build configuration to use an AGP version compatible with Gradle 8.

File: android/build.gradle (Root Project)

Note: Depending on when your Flutter project was created, you may use the legacy buildscript block or the modern plugins DSL. Most existing projects use buildscript.

buildscript {
    ext.kotlin_version = '1.9.22' // Ensure Kotlin is also updated
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        // AGP 8.1.0+ is required for Gradle 8 compatibility
        classpath 'com.android.tools.build:gradle:8.2.0'
        
        // Ensure your Kotlin Gradle plugin matches the ext version
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

tasks.register("clean", Delete) {
    delete rootProject.buildDir
}

3. Configure Java 17 in the App Module

Finally, explicitly tell the compiler to generate bytecode compatible with Java 17. If you skip this, you may encounter kapt or compile-time errors regarding source compatibility.

File: android/app/build.gradle

android {
    // Namespace is required in AGP 8+ (replace with your actual package name)
    namespace "com.example.your_app_name" 
    
    compileSdkVersion 34 // Target Android 14

    compileOptions {
        // STRICTLY REQUIRED: Target Java 17
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }

    kotlinOptions {
        // Ensure Kotlin compiles to JVM 17 bytecode
        jvmTarget = '17'
    }

    defaultConfig {
        applicationId "com.example.your_app_name"
        minSdkVersion 21 // Flutter default minimum
        targetSdkVersion 34
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    buildTypes {
        release {
            // R8 is enabled by default in AGP 8, standard settings apply
            signingConfig signingConfigs.debug
        }
    }
}

4. Verify the Environment (IDE & Terminal)

Configuration files are useless if the machine ignores them. You must ensure the terminal running flutter build is using the correct JDK.

For macOS/Linux: Check your active JDK:

java -version

If it does not say "17" (or newer), you must adjust your JAVA_HOME.

# Example for ~/.zshrc or ~/.bashrc
export JAVA_HOME="/path/to/your/jdk-17-home"
export PATH=$JAVA_HOME/bin:$PATH

For Android Studio:

  1. Open android/ folder as a project in Android Studio.
  2. Go to Settings/Preferences > Build, Execution, Deployment > Build Tools > Gradle.
  3. Set Gradle JDK to jbr-17 (JetBrains Runtime 17) or your installed JDK 17.

Why This Works

This solution resolves the deadlock by synchronizing the toolchain:

  1. Gradle 8.4 has the internal capability to run on JDK 17+.
  2. AGP 8.2.0 is designed to communicate with Gradle 8.4 and assumes the JVM environment is Java 17.
  3. jvmTarget = '17' ensures that the Kotlin compiler emits bytecode that utilizes Java 17 features (like Records or Sealed Classes) without crashing the downstream dexer (D8/R8).
  4. namespace declaration fixes the removal of the package attribute in AndroidManifest.xml, a breaking change introduced in AGP 8.0.

By performing these upgrades simultaneously, you eliminate the "Unsupported class file major version" error because the Gradle Daemon, the Plugin, and the Compiler are finally speaking the same language version.