UnsupportedClassVersionError, explained and fixed

Every compiled Java class carries a class file version number, and a Java runtime can only load classes at or below its own version. UnsupportedClassVersionError means the program was compiled with a newer JDK than the one trying to run it. The message gives both numbers, for example “class file version 61.0” (Java 17) against “this version of the Java Runtime only recognizes class file versions up to 55.0” (Java 11). Nothing is corrupt; the compiler and the runtime simply disagree about generations.

The version numbers, translated

Java 8 is class file 52, Java 11 is 55, Java 17 is 61, Java 21 is 65. Each release adds roughly one per year-version in between (Java 9 is 53, 10 is 54, 12 is 56, and so on). Read the two numbers in the error, convert them with this list, and the mismatch is fully identified: the first is what built the code, the second is what is running it.

The fixes, in order

  1. Run the program with the newer Java, when that is an option: install the JDK that matches or exceeds the compile version and make sure it is the one actually launched. Check with java -version in the same terminal or service context that runs the program; a correct JDK installed alongside an older default changes nothing.
  2. Point the environment at the right runtime: set JAVA_HOME to the newer JDK and confirm no older java earlier on the PATH shadows it. IDEs have their own project SDK and runtime settings, separate from the system, set them there too.
  3. Or compile for the older runtime: rebuild with javac --release 8 (or the target version), which restricts both the class file version and the APIs used. Setting only -source/-target is the older, weaker approach and can still reference newer APIs that fail later at runtime.
  4. In build tools, align the toolchain: Maven's maven.compiler.release or Gradle's toolchain/language version should name the version the deployment runtime actually has.
On servers and in containers, check the runtime that runs the service, not the one in an interactive shell. systemd units, Docker base images, and application servers frequently carry their own JRE. The image tag (eclipse-temurin:17 versus :11) or the service's configured JDK is where the mismatch usually lives.

Common questions

Which side should I change, compiler or runtime? Match the environment you control least. Production runtimes are usually fixed by policy, so compile with --release for that version. On a development machine, upgrading the runtime to the project's JDK is simpler.

Why did it break after a dependency update? Libraries publish jars compiled for their minimum Java. Upgrading a dependency built for Java 17 into an application running Java 11 produces this error naming the library's class, the fix is the same: raise the runtime or downgrade the library.

Does this happen with Minecraft mods and plugins? Frequently. Mods built for a newer Java than the launcher uses fail with this exact error; the remedy is running the game/server on the newer Java, which the mod's page usually specifies.

Related errors

Could not create the Java Virtual Machine · 'javac' is not recognized · ClassNotFoundException