[Solved] Maven: release version 25 not supported (Java 21+)

The Maven error “release version 25 not supported” (or 21, 27) means the JDK that runs javac is older than maven.compiler.release. Learn how to check it with mvn -v and fix it with JAVA_HOME, toolchains, IntelliJ IDEA, GitHub Actions, Docker or Gradle, plus the maven-compiler-plugin setup for Java 21 and 25.

maven

The error “release version 25 not supported” means that the JDK running the Java compiler is older than the Java release the project asks for, so javac cannot create class files for that release. Maven prints it as Fatal error compiling: error: release version 25 not supported, and the number is whatever maven.compiler.release says, e.g. 21, 25 or 27.

We see this error after we raise the Java version in a Maven project while JAVA_HOME on our machine, in the IDE or on the CI server still points to an older JDK. The fix is to compile with a JDK that is the same as, or newer than, the release in pom.xml.

The following example is the quick fix on Linux or macOS. We check which JDK Maven uses, point JAVA_HOME to a JDK 25, and build again.

mvn -v                          # Java version: 21.0.12.1 (older than release 25, so the build fails)
export JAVA_HOME=/opt/jdk25     # folder of an installed JDK 25 (Windows: setx JAVA_HOME "C:\jdk-25")
mvn -v                          # Java version: 25.0.4.1
mvn clean package               # BUILD SUCCESS

Notice that the line to read is “Java version” in the mvn -v output, not java -version, because Maven runs javac from JAVA_HOME. The sections that follow show the error in Maven, IntelliJ IDEA, Gradle and Docker, explain the cause, and give the fix for each place a build runs.

1. Release Version Not Supported in Maven, IntelliJ and Gradle

I encountered this error when upgrading an application from Java 17 to Java 21. I was using the IntelliJ IDEA IDE, and the same issue appears in other IDEs and in the terminal. Today the same error shows up for teams moving from Java 21 to Java 25, the current LTS release, or to Java 27.

The following example is a one-class Maven project that sets maven.compiler.release to 25 and uses the java.lang.IO class, which is final in Java 25. We build it with Maven 3.9.16 and maven-compiler-plugin 3.16.0, once with Temurin JDK 25.0.4.1 and once with JDK 21.0.12.1. The project is in the unsupported-class-file-version folder on GitHub, in the release-version-demo subfolder.

1.1. Maven Command Line

With JAVA_HOME pointing to JDK 21, mvn clean compile stops in the compile goal of maven-compiler-plugin. Maven passes –release 25 to javac, and javac 21 rejects it before it reads a single source file.

[INFO] --- compiler:3.16.0:compile (default-compile) @ release-version-demo ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug release 25] to target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.16.0:compile (default-compile) on project release-version-demo: Fatal error compiling: error: release version 25 not supported -> [Help 1]

The wording depends on how the project sets the Java version. Projects that still use maven.compiler.source and maven.compiler.target instead of maven.compiler.release get a different message for the same problem.

pom.xml settingMessage from javac 21
maven.compiler.release = 25Fatal error compiling: error: release version 25 not supported
maven.compiler.source and maven.compiler.target = 25Fatal error compiling: error: invalid target release: 25
maven.compiler.release = 27 on JDK 25Fatal error compiling: error: release version 27 not supported

The second message has its own article about the Maven invalid target release error, and the cause is the same.

1.2. IntelliJ IDEA

IntelliJ IDEA compiles with its own build system unless we delegate the build to Maven, so the message appears in the Build tool window with a java: prefix.

java: error: release version 25 not supported

IntelliJ IDEA takes the release from the imported pom.xml, and it takes the JDK from the Project SDK. When the Project SDK is JDK 21, the IDE build fails even if the terminal build works, as we fix in section 3.4.

1.3. Gradle

Gradle shows two variants. If the build sets options.release = 25 on the JavaCompile task and Gradle runs on JDK 21, javac gives the same message as in Maven.

* What went wrong:
Execution failed for task ':compileJava' (registered by plugin class 'org.gradle.api.plugins.JavaBasePlugin').
> Java compilation initialization error
    error: release version 25 not supported

If the build uses a Java toolchain with languageVersion = JavaLanguageVersion.of(25) and Gradle finds no JDK 25, the build fails earlier with a toolchain message.

> Cannot find a Java installation on your machine (Linux 6.18.44-fc-v70 amd64) matching: {languageVersion=25, vendor=any vendor, implementation=vendor-specific, nativeImageCapable=false}. Toolchain download repositories have not been configured.

1.4. Docker and CI Builds

In a container build, the JDK comes from the base image of the build stage. A Dockerfile that starts from maven:3.9-eclipse-temurin-21 fails on the RUN mvn -B -q package line with the Maven message from section 1.1.

10.69 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.16.0:compile (default-compile) on project release-version-demo: Fatal error compiling: error: release version 25 not supported -> [Help 1]
------
   8 | >>> RUN mvn -B -q package
--------------------
ERROR: failed to build: failed to solve: process "/bin/sh -c mvn -B -q package" did not complete successfully: exit code: 1

A GitHub Actions or Jenkins job shows the same Maven lines. The JDK there comes from the setup-java step or the agent image, so a build that passes on our laptop can fail on the CI runner.

2. The Root Cause

The error occurs when the JDK that compiles the Maven project is older than the Java release set in the configuration of the project.

Every JDK knows the Java releases up to its own version and nothing newer. The –release N option of javac, added in Java 9 by JEP 247, compiles against the API of Java N and writes class files for Java N. JDK 21 has no data about Java 25, so it stops with “release version 25 not supported”.

Flow from pom.xml with maven.compiler.release 25 to Maven running javac from JAVA_HOME, failing with JDK 21 and succeeding with JDK 25
Maven runs javac from JAVA_HOME, so a JDK 21 fails for release 25 and a JDK 25 builds class files with major version 69.

The list of releases a JDK supports is printed by javac –help. The output below is from JDK 25, and JDK 27 adds 26 and 27 to the end of the same list.

javac --help
# --release <release>
#       Compile for the specified Java SE release.
#       Supported releases:
#           8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25

The number in the error tells us the minimum JDK the build needs. The class file major version is the number older JVMs complain about later, so it helps to know both.

Error saysMinimum JDK for javacClass file major version
release version 17 not supportedJDK 1761
release version 21 not supportedJDK 2165
release version 25 not supportedJDK 2569
release version 26 not supportedJDK 2670
release version 27 not supportedJDK 2771

We check the JDK that compiles the project with the command mvn -v in the terminal. The output shows JDK 21 in our example, while the project asks for release 25.

$ mvn -v

Apache Maven 3.9.16 (2bdd9fddda4b155ebf8000e807eb73fd829a51d5)
Maven home: /opt/maven
Java version: 21.0.12.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-21-openjdk-amd64
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "6.18.44-fc-v70", arch: "amd64", family: "unix"

The mvn script reads the JAVA_HOME environment variable, so the Java version in JAVA_HOME and the release in pom.xml must fit together. The command java -version is not a reliable check for this, because the java command on the PATH can be a different JDK. On the same machine, JAVA_HOME pointed to JDK 21 while the java command on the PATH was JDK 25.

$ echo $JAVA_HOME
/usr/lib/jvm/java-21-openjdk-amd64

$ java -version
openjdk version "25.0.4.1" 2026-08-18 LTS

The JDK version configured for the Maven compiler plugin can come from a property, from the plugin’s configuration block, or from a parent POM such as spring-boot-starter-parent. In our example, it is one property that asks for Java 25.

<properties>
  <maven.compiler.release>25</maven.compiler.release>
</properties>

3. The Solution

To solve the error, the JDK in JAVA_HOME and the release set for the compiler plugin must fit together. The release can be lower than the JAVA_HOME version, but it must not be higher.

JAVA_HOMEpom.xml releaseWorks?
2121YES
2521YES
2725YES
2125NO, release version 25 not supported
2527NO, release version 27 not supported

Which fix fits depends on whether the machine can use a newer JDK and whether the code needs the newer release. The decision tree shows the four options, and the sections after it give the commands for each place a build runs.

Decision tree for the release version not supported error, leading to JAVA_HOME, Maven toolchains, a lower release or a Docker or CI build with JDK 25
Install or select a JDK 25 wherever javac runs; lower the release only when the code does not need Java 25.

3.1. Point JAVA_HOME to a Newer JDK

On a developer machine, the standard fix is to install JDK 25 and point JAVA_HOME to it. On Linux and macOS, we set the variable in the shell profile (for example ~/.bashrc or ~/.zshrc) so every new terminal picks it up.

# Linux
export JAVA_HOME=/opt/jdk25
export PATH="$JAVA_HOME/bin:$PATH"

# macOS (path of the installed JDK 25)
export JAVA_HOME=$(/usr/libexec/java_home -v 25)

mvn -v      # Java version: 25.0.4.1, runtime: /opt/jdk-25.0.4.1+1

On Windows, we change JAVA_HOME in the System Properties dialog under Environment Variables, or with setx, and check it in a new Command Prompt. The Maven installation guide for Windows shows the dialog.

setx JAVA_HOME "C:\Program Files\Eclipse Adoptium\jdk-25.0.4.1-hotspot"

echo %JAVA_HOME%

# Output

C:\Program Files\Eclipse Adoptium\jdk-25.0.4.1-hotspot

After we point JAVA_HOME to a Java 25 distribution and open a new terminal window, the project compiles successfully.

Open a new terminal window after updating JAVA_HOME, because environment variables take effect only in newly launched terminals. The same applies to IntelliJ IDEA and other IDEs, which we close and open again for the change to take effect.

3.2. Compile With a Different JDK Using Maven Toolchains

Sometimes Maven must keep running on JDK 21, for example because other projects on the same build server need it. Maven toolchains solve that case. Maven runs on the JDK in JAVA_HOME, and the compiler, Surefire and other toolchain-aware plugins use the JDK we pick in the project.

First, we list the installed JDKs in ~/.m2/toolchains.xml, one toolchain entry per JDK.

<toolchains>
  <toolchain>
    <type>jdk</type>
    <provides>
      <version>25</version>
    </provides>
    <configuration>
      <jdkHome>/opt/jdk25</jdkHome>
    </configuration>
  </toolchain>
</toolchains>

Next, the project asks for a JDK 25 with the maven-toolchains-plugin. In the example project, the plugin sits in a profile named jdk-toolchain, so the normal build stays the same.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-toolchains-plugin</artifactId>
  <version>3.3.0</version>
  <executions>
    <execution>
      <goals>
        <goal>toolchain</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <toolchains>
      <jdk>
        <version>25</version>
      </jdk>
    </toolchains>
  </configuration>
</plugin>

With JAVA_HOME still on JDK 21, the build succeeds. The -t option points to a toolchains file in the project folder; without it, Maven reads ~/.m2/toolchains.xml.

$ mvn clean package -Pjdk-toolchain -t toolchains-example.xml

[INFO] --- toolchains:3.3.0:toolchain (default) @ release-version-demo ---
[INFO] Required toolchain: jdk [ version='25' ]
[INFO] Found matching toolchain for type jdk: JDK[/opt/jdk25]
[INFO] --- compiler:3.16.0:compile (default-compile) @ release-version-demo ---
[INFO] Toolchain in maven-compiler-plugin: JDK[/opt/jdk25]
[INFO] Compiling 1 source file with javac [forked debug release 25] to target/classes
[INFO] --- surefire:3.5.4:test (default-test) @ release-version-demo ---
[INFO] Toolchain in maven-surefire-plugin: JDK[/opt/jdk25]
[INFO] BUILD SUCCESS

We can see that Surefire also picks the JDK 25 toolchain for the test JVM, which matters because Java 25 class files do not load on a JDK 21 JVM.

3.3. Lower maven.compiler.release

If the code does not use Java 25 language features or APIs, we can lower the release to the JDK we have. A JDK always compiles for older releases, so JDK 21 builds maven.compiler.release 21 without complaint, and the class files also run on Java 21.

mvn clean package -Dmaven.compiler.release=21     # one build only

For a permanent change, we edit the property in pom.xml. If the code does use a Java 25 API, javac checks it against the Java 21 API and fails with a normal compilation error, which is how we know the code needs the newer release. Our example uses IO.println(), so release 21 fails even on JDK 25.

[ERROR] COMPILATION ERROR :
[ERROR] .../release/ReleaseInfo.java:[13,5] cannot find symbol
  symbol:   variable IO
  location: class com.howtodoinjava.release.ReleaseInfo

3.4. Fix the JDK in IntelliJ IDEA

IntelliJ IDEA keeps its own JDK settings, separate from JAVA_HOME, so the terminal build can pass while the IDE build fails. We check three settings, and the Maven projects in IntelliJ guide covers the import itself.

  • In File > Project Structure > Project, set the SDK to JDK 25 and the Language level to 25 (or “SDK default”).
  • In Settings > Build, Execution, Deployment > Compiler > Java Compiler, clear the Project bytecode version and any Per-module bytecode version entry that says 21, so IntelliJ IDEA takes the release from pom.xml.
  • In Settings > Build, Execution, Deployment > Build Tools > Maven > Runner, set JRE to JDK 25 (or “Use Project JDK”). Maven goals started from the IDE use this JDK, not JAVA_HOME.

After the changes, we reload the Maven project from the Maven tool window and rebuild. The JDK for importer setting under Maven > Importing is used for reading the POM, so it does not decide which javac compiles the code.

3.5. Set the Java Version in GitHub Actions

A GitHub-hosted runner comes with a preinstalled JDK that is often older than the latest release. The setup-java action installs the JDK we ask for and sets JAVA_HOME for the next steps.

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-java@v6
        with:
          distribution: temurin
          java-version: '25'
          cache: maven
      - name: Build
        run: mvn -B package

The java-version in the workflow must be the same as, or higher than, maven.compiler.release in pom.xml. When we upgrade the release in the POM, we change the workflow in the same commit. Jenkins and GitLab CI follow the same rule, because the JDK tool or the job image decides which javac runs.

3.6. Use a Docker Image With the Right JDK

In a multi-stage Dockerfile, the tag of the Maven image picks the JDK. For release 25, the build stage needs an image with JDK 25 or newer, and the runtime stage needs at least a Java 25 JRE. The Docker image for a Spring Boot app article explains the stages in more detail.

# Build stage: the JDK in this image runs javac, so it must be 25 or newer
FROM maven:3.9-eclipse-temurin-25 AS build
WORKDIR /src
COPY pom.xml .
COPY src ./src
RUN mvn -B -q package

# Runtime stage: a Java 25 JRE loads class file major version 69
FROM eclipse-temurin:25-jre
COPY --from=build /src/target/release-version-demo-1.0.0.jar /app/app.jar
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

With the 25 tag in both stages, the image builds and the app reports the Java version and class file version it runs with.

$ docker build -t release-demo .
$ docker run --rm release-demo
Running on Java 25
Class file major version 69

3.7. Use a Gradle Java Toolchain

Gradle has its own Java toolchains, which work like Maven toolchains. Gradle runs on any supported JDK, and the compile, test and run tasks use the JDK the toolchain asks for. With the foojay resolver plugin in settings.gradle, Gradle downloads a matching JDK when none is installed, which fixes the “Cannot find a Java installation” message from section 1.3.

plugins {
    id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
}
rootProject.name = 'release-version-demo'
plugins {
    id 'java'
    id 'application'
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(25)
    }
}

application {
    mainClass = 'com.howtodoinjava.release.ReleaseInfo'
}

With Gradle 9.8.0 running on JDK 21, gradle run downloads JDK 25 on the first build, compiles the class and runs it on Java 25.

> Task :compileJava
> Task :run
Running on Java 25
Class file major version 69

BUILD SUCCESSFUL in 41s

4. Maven Compiler Plugin Configuration

The maven-compiler-plugin has a release parameter that maps to javac’s –release option. We prefer it over source and target, because release also checks that the code uses only the API of that Java version. The latest stable plugin version is 3.16.0, and the 4.0.0 line is still in beta for Maven 4.

For most projects, one property is enough. Maven 3.9.16 binds maven-compiler-plugin 3.15.0 by default, and the default changes with each Maven release, so we also pin the plugin version.

<properties>
  <maven.compiler.release>25</maven.compiler.release>
</properties>

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.16.0</version>
    </plugin>
  </plugins>
</build>

For Java 21, we change only the number to 21. If we prefer to keep the setting next to the plugin, the release element in the plugin’s configuration does the same job as the property.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.16.0</version>
  <configuration>
    <release>21</release>
  </configuration>
</plugin>

A Spring Boot application that inherits from spring-boot-starter-parent sets the Java version with the java.version property. The parent copies it into maven.compiler.release, as shown in Spring Boot starter parent, so we change java.version and leave the compiler plugin alone. The Java version in Maven article compares all the ways to set it.

<properties>
  <java.version>25</java.version>
</properties>

To get a clearer message than the javac error, we can let the build fail before compilation with the requireJavaVersion rule of the Maven Enforcer Plugin. The main project in the same GitHub folder uses the rule.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-enforcer-plugin</artifactId>
  <version>3.6.3</version>
  <executions>
    <execution>
      <id>require-jdk-25</id>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <requireJavaVersion>
            <version>[25,)</version>
            <message>Build this project with JDK 25 or newer (JAVA_HOME points to an older JDK).</message>
          </requireJavaVersion>
        </rules>
      </configuration>
    </execution>
  </executions>
</plugin>

On JDK 21, the build stops in the validate phase with our own message, so a new team member sees the fix in the error.

[ERROR] Rule 0: org.apache.maven.enforcer.rules.version.RequireJavaVersion failed with message:
[ERROR] Build this project with JDK 25 or newer (JAVA_HOME points to an older JDK).

5. Release Version Not Supported FAQs

Three related messages and one runtime failure often show up next to this error in Stack Overflow threads and search results.

5.1. Why Does My Build Say invalid target release Instead?

The build sets source and target instead of release. Javac checks the target first and reports invalid target release: 25 (or invalid source release: 25 when only the source is too high). The cause and the fix are the same as for “release version 25 not supported”, and we can switch to maven.compiler.release while fixing it.

5.2. Why Does a New JDK Say release version 7 not supported?

The JDK is too new for the release, not too old. Each JDK drops the oldest releases, and JDK 21, JDK 25 and JDK 27 all start at release 8, so old projects with 1.7, 7, 6 or 5 in the POM fail with “release version 7 not supported”. Projects that set no Java version in pom.xml get the default of the compiler plugin, which was 1.5 in versions before 3.8.0. We raise the release to 8 or higher, or build the old project with the old JDK through a toolchain.

5.3. Can JDK 25 Compile Code for Java 21?

Yes. JDK 25 accepts –release 21 and writes class files with major version 65, which run on Java 21 and newer. The code must use only the Java 21 API, otherwise javac reports cannot find symbol, as we saw in section 3.3.

5.4. Why Does the App Fail at Runtime After a Successful Build?

The build used a JDK that is new enough, but the JVM, test runner or tool that loads the classes is older. That shows up as UnsupportedClassVersionError or “Unsupported class file major version 69”, which is a different error with its own fixes, covered in Unsupported class file major version 69.

6. Conclusion

The error “release version 25 not supported” can appear for any Java release when we upgrade a project, for example to Java 21, 25 or 27. The cause is always a JDK that is older than the release in pom.xml.

The number in the error is the release from pom.xml, and the JDK that runs javac must be at least that version. We check that JDK with mvn -v, not with java -version, and fix it in each place the build runs, namely JAVA_HOME, the IDE, the CI job and the Docker image. Toolchains help when Maven itself must stay on an older JDK.

After updating JAVA_HOME, we relaunch the IDE or the terminal window, because only a new process reads the new value.

7. References

Happy Learning !!

Source Code on Github

Leave a Comment

  1. Is there a way that can just use java 21 in my sub module pom.xml and let other models and parent pom.xml work on java 1.8?

  2. This doesn’t work for me:
    $ grep -F -A 4 'maven-compiler-plugin' pom.xml
           <artifactId>maven-compiler-plugin</artifactId>
           <version>3.11.0</version>
           <configuration>
             <release>21</release>
           </configuration>

    $ $JAVA_HOME/bin/java --version | head -1
    openjdk 21.0.3 2024-04-16

    Still getting
    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.11.0:compile (default-compile) on project websocket-resources: Fatal error compiling: error: release version 21 not supported -> [Help 1]

  3. ultimately your JAVA_HOME located Java version and the version used in pom.xml should match.

    THIS!!!! THIS IS THE ANSWER TO MY PROBLEM!!! THAAAAANK YOU!!!!!!!

Comments are closed.

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.