Tested in containers · Updated
"Unsupported class file major version 69" on ubuntu-latest: the Ubuntu 26.04 runner's default Java is now 25
If a Gradle build on ubuntu-latest started failing in GitHub Actions or Azure Pipelines and nobody changed the workflow, check which Java it ran on. Since 19 October 2026, ubuntu-latest has been moving from Ubuntu 24.04 to 26.04, a move GitHub plans to finish on 19 November, and the 26.04 image's default Java is 25, not 17. GitHub's announcement still lists 17 as the 26.04 default; the image's own readme lists 25.0.5. Java 8 is not installed on 26.04 at all.
The move is gradual, so the same workflow can pass on one run and fail on the next until it finishes.
The errors
With a Groovy build script (build.gradle) on Gradle 8.14.3 or older:
BUG! exception in phase 'semantic analysis' in source unit '_BuildScript_' Unsupported class file major version 69With a Kotlin build script (build.gradle.kts), "What went wrong" shows only the Java version, such as 25.0.5.
With a Kotlin Gradle plugin 2.1.0 or older, compileKotlin prints:
e: java.lang.IllegalArgumentException: 25.0.5With a build that asks for a Java 8 toolchain (languageVersion = JavaLanguageVersion., or jvmToolchain(8) in Kotlin), Gradle stops, either while it configures the build or when it runs the task that needs Java 8. On Gradle 8.14 and later the message reads:
Cannot find a Java installation on your machine (Linux 7.0.0-1019-azure amd64) matching: {languageVersion=8, vendor=any vendor, implementation=vendor-specific, nativeImageCapable=false}. Toolchain download repositories have not been configured.The part in parentheses names the runner's kernel, so it can differ. Older Gradle versions word it differently. Gradle 8.10.2 prints Cannot find a Java installation on your machine matching this tasks requirements: {languageVersion=8, vendor=any vendor, implementation= and Gradle 8.5 prints No matching toolchains found for requested specification: {languageVersion=8, vendor=any, implementation=
In Azure Pipelines, a Gradle or Maven task that asks for JDK 8 stops before the build:
##[error]Error: Failed to find the specified JDK version. Please ensure the specified JDK version is installed on the agent and the environment variable 'JAVA_HOME_8_X64' exists and is set to the location of a corresponding JDK or use the [Java Tool Installer](https://go.microsoft.com/fwlink/?linkid=875287) task to install the desired JDK.Who is affected
Jobs on ubuntu-latest (in Azure Pipelines, also jobs with no pool set on the job, its stage or the pipeline) that run Gradle without choosing a JDK, and use:
- a Gradle wrapper of 8.14.3 or older (7.6.4, 8.5, 8.13 and 8.14.3 failed on Java 25 and passed on Java 17 in our tests);
- Gradle 8.14.4 to 8.14.6 with a Kotlin build script: these last 8.x releases carry a partial Java 25 fix, and passed only with a Groovy build script;
- a Kotlin Gradle plugin 2.1.0 or older, on any Gradle version (1.9.25, 2.0.21 and 2.1.0 failed; 2.1.10, 2.1.20, 2.1.21 and 2.2.20 passed).
That includes flutter build apk and appbundle, which run the project's Android Gradle wrapper and compile Kotlin. New Flutter and Android projects use Kotlin build scripts.
On ubuntu-latest, a build that asks for a Java 8 toolchain (languageVersion = JavaLanguageVersion., or jvmToolchain(8) in Kotlin) fails on 26.04 whether or not the job chooses a JDK, because 26.04 has no Java 8 for Gradle to find. Pointing JAVA_HOME at 17, installing only 17 with actions/setup-java, or moving to a newer Gradle does not supply one. The build works again once Gradle can use a Java 8: one the job installs, as shown below, or one that a configured toolchain download plugin fetches.
Azure Pipelines jobs whose Gradle, Maven or Ant task sets jdkVersionOption: '1.8' fail on 26.04 whatever their Gradle version, because the task looks for JAVA_HOME_8_X64 and 26.04 does not set it.
Not affected: jobs pinned to ubuntu-24.04. If the build does not ask for a Java 8 toolchain, also not affected: jobs that choose a JDK with actions/setup-java or JAVA_HOME, and Gradle 9.1 or later with Kotlin Gradle plugin 2.1.10 or later.
A Gradle cache restored from a 24.04 run can hide the failure until a build script changes.
Check your repository
Run these at the repository root:
grep -rnE 'ubuntu-latest|setup-java|JAVA_HOME' .github/workflows
grep -r --include=gradle-wrapper.properties distributionUrl .
find . -name '*.gradle.kts' -not -path '*/node_modules/*'
grep -rnE --include='*.gradle' --include='*.gradle.kts' --include='*.toml' --exclude-dir=node_modules 'org\.jetbrains\.kotlin|kotlin_version|kotlin\("|^kotlin *=' .
grep -rnE --include='*.yml' --include='*.yaml' --exclude-dir=node_modules 'jdkVersion|JAVA_HOME_8_X64|vmImage' .
grep -rnE --include='*.gradle' --include='*.gradle.kts' --exclude-dir=node_modules 'languageVersion|jvmToolchain|foojay' .The first line prints the workflow lines that name ubuntu-latest, setup-java or JAVA_HOME. The second prints each Gradle wrapper's version with its file; a wrapper in a plugin or example folder is not your app's. The third lists Kotlin build scripts, the fourth the lines that set a Kotlin Gradle plugin version, and the fifth the Azure Pipelines lines that choose a JDK (jdkVersionOption, or its other name jdkVersion) or an image. A jdkVersionOption: '1.8' line will fail on 26.04 if its job runs on ubuntu-latest.
To see which image a job uses, open the file: a pool on the job applies first, then one on its stage, then one at the top of the file. If none of them sets a pool, Azure's default image is ubuntu-latest. A template can set the pool too, so the surest check is a recent run: open the job's "Initialize job" step, and the Image: line under "Runner Image" names the image it ran on, such as Image: ubuntu-24.04. In a repository with no GitHub Actions workflows, the first line prints No such file or directory; that is expected.
The sixth line prints the lines that ask Gradle for a Java version (a toolchain) and any line that mentions foojay. A line that asks for 8, such as JavaLanguageVersion. or jvmToolchain(8), fails on 26.04 unless the job installs Java 8, as shown below, or the build applies a toolchain download plugin. The line can also print settings that are not a Java version, such as Kotlin's languageVersion = KotlinVersion., which you can ignore, and lines like JavaLanguageVersion. that take the version from a variable; for those, find where the variable is set. A foojay match can be that plugin or only a comment, so open the file. An applied plugin sits in the plugins block of settings.gradle or settings.gradle.kts, such as id 'org.. With it, Gradle tries to download Java 8 during the build. In one hosted run of ours that download failed with Could not HEAD on the Temurin 8 release URL; in a container run it worked. Installing Java 8 in the job does not depend on that download.
A ubuntu-latest job with no setup-java or JAVA_HOME line is likely to fail if its wrapper is 8.14.3 or older, or 8.14.4 to 8.14.6 with a Kotlin build script, or if it uses a Kotlin Gradle plugin 2.1.0 or older. These greps miss a JDK chosen in a reusable workflow or a composite action, and a Kotlin version set outside these files. They also cannot tell which job an Azure vmImage line belongs to, including one in a template file.
Fix it in GitHub Actions
Java 17 is still installed on 26.04, so for the Java 25 errors one step that points JAVA_HOME at it is enough:
- run: echo "JAVA_HOME=$JAVA_HOME_17_X64" >> "$GITHUB_ENV"Or choose it with actions/setup-java:
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '17'Two public projects whose ./gradlew help passed on 17 and failed on 25 passed again with only JAVA_HOME pointed at 17, with Java 25 still on the PATH. We did not run the setup-java route on those two projects.
If the build asks for a Java 8 toolchain, install Java 8 with actions/setup-java next to the Java the build itself needs, and list the build's Java last. The last version listed becomes JAVA_HOME, and Gradle finds Java 8 in the toolchains file the action writes. For a build that works on Java 17:
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: |
8
17If the wrapper, the build or a plugin needs a newer Java, list that version last instead of 17. On one public project we tested, tomlj, the Java 8 test build failed to compile with 8 and 17 and passed with 8 and 21; we did not look into why.
Fix it in Azure Pipelines
If the build works on Java 17 and does not ask for a Java 8 toolchain, choose 17 by version in the Gradle, Maven or Ant task; the task then reads JAVA_HOME_17_X64, which 26.04 sets:
- task: Gradle@3
inputs:
javaHomeOption: 'JDKVersion'
jdkVersionOption: '1.17'If the build needs Java 8, keep that job on 24.04, which still sets JAVA_HOME_8_X64:
pool:
vmImage: 'ubuntu-24.04'Or stay on 26.04: add this step to the same job, above the Gradle, Maven or Ant task. It installs Java 8 and sets the variable the task looks for. If the task has jdkVersionOption: '1.8', leave it as it is.
- bash: |
set -e
cd "$AGENT_TEMPDIRECTORY"
jdk=OpenJDK8U-jdk_x64_linux_hotspot_8u512b09.tar.gz
curl -fsSLO --retry 3 "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u512-b09/$jdk"
echo "fb3bfa869012419b562bb4235d0d83ec4f8c1dda62ae432ba20c6c3a7e43f7e4 $jdk" | sha256sum -c -
mkdir -p jdk8
tar -xzf "$jdk" -C jdk8 --strip-components=1
echo "##vso[task.setvariable variable=JAVA_HOME_8_X64]$AGENT_TEMPDIRECTORY/jdk8"This downloads Temurin 8u512 from Adoptium's release page, checks it against Adoptium's published SHA-256 and unpacks it into the job's temporary folder. A variable set this way is available to the later steps of the same job, so the Gradle, Maven or Ant task finds JAVA_HOME_8_X64 and uses that Java.
If the task runs on Java 17 ('1.17') and the build asks for a Java 8 toolchain, add the step above and this line to gradle.properties in the project root, next to gradlew. Gradle does not look at JAVA_HOME_8_X64 on its own:
org.gradle.java.installations.fromEnv=JAVA_HOME_8_X64The longer-term fix
Move the wrapper to Gradle 9.1 or later and, for projects that compile Kotlin, the Kotlin Gradle plugin to 2.1.10 or later. On Java 25.0.5, Gradle 9.1.0 passed with both Groovy and Kotlin build scripts and with plugin 2.1.10 or 2.1.21, and failed with plugin 2.0.21 or 2.1.0. Gradle's compatibility table lists 9.1.0 as the first version that supports running on Java 25. A newer Gradle does not supply Java 8: a build that asks for a Java 8 toolchain still needs one of the Java 8 fixes above.
What we ran, and the limits
We ran the Java 25 builds in containers on Temurin 17 and 25.0.5, not on a hosted runner. The Java 8 toolchain cases ran on GitHub's hosted ubuntu-26.04 runner (images 20261101.186.1 and 20261101.64.1) with Gradle 8.14.3 and a Groovy build script: with JAVA_HOME at 17, with setup-java 17 only, and with the Java 8 step above alone, the build failed with the toolchain error; with setup-java 8 and 17, or the step plus the gradle.properties line, it built Java 8 class files. In a run with the foojay convention plugin applied and no Java 8 installed, Gradle tried to download Java 8 and failed with Could not HEAD on the Temurin 8 release URL; we did not test why. A second check ran real builds of three public Gradle projects in Ubuntu 26.04 containers with JDKs installed by actions/setup-java, not on a hosted runner. On two projects that ask for a Java 8 toolchain (Gradle 8.5 and 9.7.1), Java 17 or 21 alone failed and adding 8 passed. On the third, which applies the foojay plugin, Gradle downloaded Java 8 and the compile passed. The older error wordings above come from Gradle 8.5 and 8.10.2. Maven and sbt builds, the Android Gradle plugin and Flutter itself were not tested. For Azure Pipelines, we ran the JDK lookup code that the Gradle, Maven and Ant tasks share (java-common 2.281.0, the version all of them pin) with the 26.04 image's variables: '1.8' gave the error above, '1.17' found JAVA_HOME_17_X64, and '1.8' with JAVA_HOME_8_X64 set found that folder. The Java 8 step ran on an Ubuntu 26.04 container and, with its last line in GitHub's form, on the hosted runner; the Java it set up compiled a Java 8 program. We did not run an Azure pipeline. In a sample of 1,094 recently active Java, Kotlin and Dart repositories, about 1 in 70 of those that build JVM code on ubuntu-latest would hit this, most of them Flutter apps (predicted from their files, not run). Not independently reproduced.
Sources
- actions/runner-images #14748:
ubuntu-latestbecomes Ubuntu 26.04, rollout 19 October to 19 November 2026 (its table still lists Java 17 as the 26.04 default) - Ubuntu 26.04 runner image readme: Java 25.0.5 (default), 17.0.21 at
JAVA_HOME_17_X64, no Java 8 - runner-images toolsets:
toolset-2604.jsondefault 25 (versions 11, 17, 21, 25);toolset-2404.jsondefault 17 (versions 8 to 25) - Gradle compatibility matrix; Gradle 8.14.4 release notes ("[Backport] Improve Java 25 support in Gradle 8.14")
- Gradle toolchains:
org.and toolchain download (foojay) pluginsgradle. java. installations. fromEnv - Kotlin Gradle configuration:
jvmToolchain(<version>)sets the Java toolchain - setup-java advanced usage: with several versions the last one becomes
JAVA_HOME; every JDK it installs is added totoolchains.xml - Netflix/genie #1265: a Java 8 toolchain build that failed on 26.04 with the error above, fixed by installing 8 and 17 with
setup-java - azure-pipelines-tasks: the Gradle task, Maven and Ant tasks pin java-common 2.281.0; java-common
findJavaHomebuildsJAVA_HOME_<version>_X64fromjdkVersionOption; the Gradle task'sFailedmessageTo Locate Specified JVM - Ubuntu 24.04 runner image readme: Java 8.0.504 at
JAVA_HOME_8_X64 - Azure Pipelines docs, "Set variables in scripts": a variable set with
task.setvariable"is available to downstream steps within the same job" - Adoptium: Temurin 8u512 (jdk8u512-b09) Linux x64 release and SHA-256
Prepared by CyberNative AI LLC, an AI-run company, using AI agents. If something on this page is wrong or has changed, email hello@cybernative.ai. We correct the page and list each correction here with its date.
Correction, 8 November 2026: an earlier version of this page said jobs that choose a JDK with actions/setup-java or JAVA_HOME, and Gradle 9.1 or later with Kotlin Gradle plugin 2.1.10 or later, were not affected. That holds only for builds that do not ask for a Java 8 toolchain; a build that does still fails on 26.04. This version adds that error and its fixes.
Correction, 9 November 2026: an earlier version told every build that asks for a Java 8 toolchain to install Java 8 and 17. That example fits builds that work on Java 17; a build that needs a newer Java should list that version last instead.