Java invalid target release — Wrong JDK or Compiler Flag
Fix "invalid target release: N" by installing the matching JDK, aligning maven.compiler.release, and checking JAVA_HOME.
Symptoms
- Compilation fails with "invalid target release: 17"
- The build works on one machine and fails on CI
- Maven or Gradle reports the target version while java -version shows another
Possible causes
- The compiler runs on an older JDK than the requested target release
- maven.compiler.release or sourceCompatibility exceeds the installed JDK
- JAVA_HOME points at a different JDK than the one on PATH
Diagnosis steps
Compare compiler JDK with target release
mvn -version && javac -version && echo "$JAVA_HOME"Interpretation
The runtime JDK must be at least the requested release; a mismatch produces invalid target release.
Check configured release
grep -rn "release>\|source>\|target>\|compiler.release" pom.xml build.gradleInterpretation
The configured release tells you which JDK to install or which value to lower.
Root cause
javac cannot produce bytecode targeting a release newer than the JDK performing compilation. Requesting release 17 from a JDK 11 toolchain therefore fails with invalid target release before any class is emitted.
Fix
Install and select the matching JDK (set JAVA_HOME and PATH), align maven.compiler.release/sourceCompatibility with the available JDK, or use toolchains to pin the compiler JDK independently of the runtime.
Risk note
Lowering the target to match an old JDK may ship bytecode lacking features and missed security fixes; prefer installing the correct JDK.
Verify the fix
Rebuild and confirm compilation succeeds; check the produced class file version matches the intended release with javap -v.
Symptoms
This guide profiles the failure behind “Java invalid target release — Wrong JDK or Compiler Flag”. It walks through the observable symptoms, a reproducible diagnosis path, the underlying root cause, the concrete fix, and how to verify the change and prevent a regression.
Observed symptoms include:
- Compilation fails with “invalid target release: 17”
- The build works on one machine and fails on CI
- Maven or Gradle reports the target version while java -version shows another
Reproduce and Diagnose
Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.
Step 1: Compare compiler JDK with target release
mvn -version && javac -version && echo "$JAVA_HOME"
The runtime JDK must be at least the requested release; a mismatch produces invalid target release.
Step 2: Check configured release
grep -rn "release>\|source>\|target>\|compiler.release" pom.xml build.gradle
The configured release tells you which JDK to install or which value to lower.
Likely contributors, in order of frequency:
- The compiler runs on an older JDK than the requested target release
- maven.compiler.release or sourceCompatibility exceeds the installed JDK
- JAVA_HOME points at a different JDK than the one on PATH
Root Cause
javac cannot produce bytecode targeting a release newer than the JDK performing compilation. Requesting release 17 from a JDK 11 toolchain therefore fails with invalid target release before any class is emitted.
The Fix
Install and select the matching JDK (set JAVA_HOME and PATH), align maven.compiler.release/sourceCompatibility with the available JDK, or use toolchains to pin the compiler JDK independently of the runtime.
Watch out: Lowering the target to match an old JDK may ship bytecode lacking features and missed security fixes; prefer installing the correct JDK.
<!-- Maven toolchains: compile with JDK 17 regardless of runtime -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>17</release>
</configuration>
</plugin>
# verify the bytecode version
javap -v target/classes/com/example/Main.class | grep 'major version'
Verify and Prevent
Rebuild and confirm compilation succeeds; check the produced class file version matches the intended release with javap -v.
Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.
This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.