Tested fix · Updated
NoClassDefFoundError or "invalid header field (line 1)" on Oracle GraalVM 25: the JIT bug and the flag that stops it
On Oracle GraalVM for JDK 25, the Graal JIT compiler can compile the JDK's own manifest reader wrongly. After that, every JAR manifest that JVM reads fails with java.io.IOException: invalid header field (line 1). You see classes that are in the jar fail to load, with a NoClassDefFoundError or Service at startup, or a javac build that fails on a dependency jar and passes when you run it again. Oracle has fixed it in the compiler's main branch, not yet in a JDK 25 release. Until then, this flag stopped it in our runs:
-Djdk.graal.Vectorization=false
With Java Flight Recorder on, 39 of 48 fresh Oracle GraalVM 25.0.4 JVMs broke. With the flag added, 0 of 48 broke. GraalVM Community Edition and Eclipse Temurin did not break in our runs. In our x86_64 runs on 25.0.4, and in the second bug report's measurements, it appeared only with JFR on. But neither report says JFR was on when the failure was first seen: the first in ordinary javac builds on AMD64, the second in production on aarch64. The second report also measured broken JVMs on 25.0.2, 25.0.4, 25.0.5 and 25.0.5.0.2. So treat any Oracle GraalVM 25 JVM as exposed.
Is this you?
The error. Search your logs for
invalid header field.line 1is the most common, but other line numbers appear too (the second bug report listsline 831,line 4124andline 13450, and our runs saw others), so search without the number. A class that is in the jar but fails to load, or a service provider that "is not found", can be this error underneath. The second bug report explains why: the class loader reads the jar's manifest before it defines the class, and drops the exception.The JVM. Run
java -versionwith the same Java your application or build uses. It is affected if the output names Oracle GraalVM 25, like this from the current download:java version "25.0.4" 2026-07-21 LTS Java(TM) SE Runtime Environment Oracle GraalVM 25.0.4+7.1 (build 25.0.4+7-LTS-jvmci-b01) Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 25.0.4+7.1 (build 25.0.4+7-LTS-jvmci-b01, mixed mode, sharing)You also have it if a GitHub Actions workflow uses
graalvm/setup-graalvmwithjava-version: '25'and nodistribution, ordistribution: 'graalvm': that is Oracle GraalVM. Oracle's container imagescontainer-registry.andoracle. com/ graalvm/ jdk:25 container-registry.contain Oracle GraalVM for JDK 25.oracle. com/ graalvm/ native-image:25 A test run that does not fail does not clear you. Whether a JVM breaks depends on timing and on which jars it reads.
Turn off the faulty optimization
Add -Djdk.graal. to every Oracle GraalVM 25 JVM that reads jars. This option turns off one group of the Graal compiler's optimizations. Its own help text says: "Enables vectorization. This is a global switch to enable/disable all vectorization-related optimizations." It is a Boolean, true by default, in Oracle GraalVM.
For everything in one shell, job or container, set it in JAVA_TOOL_OPTIONS. JVMs started from there read it, including javac, the JVM that runs Maven, and JVMs those start in turn, such as test forks, unless the build clears their environment:
export JAVA_TOOL_OPTIONS=-Djdk.graal.Vectorization=false
java -versionjava -version must now start with this line, and then print the version as before:
Picked up JAVA_TOOL_OPTIONS: -Djdk.graal.Vectorization=falseIf JAVA_TOOL_OPTIONS already has a value, add the flag at the end of it, after a space. Setting it as above replaces your other options.
In a GitHub Actions workflow, set it for the job:
env:
JAVA_TOOL_OPTIONS: -Djdk.graal.Vectorization=falseIn a Dockerfile built on an Oracle GraalVM 25 image:
ENV JAVA_TOOL_OPTIONS=-Djdk.graal.Vectorization=falseIf JAVA_TOOL_OPTIONS is also set when the container starts, that value replaces the one in the image, so add the flag there too. Common places are Compose environment:, docker run -e, a Kubernetes env: entry, and agent injectors such as the OpenTelemetry Operator's Java instrumentation.
After any of these changes, find the Picked up JAVA_TOOL_OPTIONS line in the next build or container log and check that it contains -Djdk.graal.. The line alone is not enough: it appears whenever the variable is set, with or without the flag.
The flag is safe in jobs that also run other JDKs: GraalVM Community Edition 25 and Eclipse Temurin 25 accepted it and ran normally in our check.
For one application only, put the flag on its java command line instead, before -jar or the class name:
java -Djdk.graal.Vectorization=false -jar app.jarCheck these before you roll it out:
- Copy the flag exactly. A misspelt
jdk.graaloption stops every JVM that reads it. WithVectorizaton,java,javacandmvnall exited with status 1 and printedError parsing Graal options: Could not find option Vectorizaton. Runjava -versiononce after the change; it shows this error at once. - The extra line goes to standard error. Every JVM prints
Picked up JAVA_TOOL_OPTIONS: …on stderr. A script that fails when a command writes to stderr, or that reads the first line ofjava -version, may need a change. If that is a problem, use the command-line flag. - The speed cost is not measured. We did not measure how much slower code runs with this optimization off. Measure your own workload if speed matters.
- Remove it after the fix ships. When you are on a release that has the fix (below), take the flag out.
If you would rather not touch the Graal compiler's options, -XX:-UseJVMCICompiler makes the JVM compile with HotSpot's C2 compiler instead of Graal. It also gave 0 broken JVMs in our runs. It is a bigger change: it replaces the whole JIT compiler, not one group of optimizations.
What did not work:
-Djdk.graal.: 18 of 24 JVMs still broke.VectorIntrinsics= false - Disabling
RemoveEmptyLoops, which a maintainer suggested in the second report's thread. The reporter confirmed it helped on a 25.0.5.0.2 build, which is not a public download. Oracle GraalVM 25.0.4 and 25.0.3, the public downloads, have no option with that name: with-Djdk.graal.the JVM does not start (RemoveEmptyLoops= false Error parsing Graal options: Could not find option RemoveEmptyLoops, exit status 1).
What we measured
We ran the test program from the bug report, oracle/graal#14797. It reads the manifest of the janino-3.1.12.jar from Maven Central 2,000 times in one JVM and checks each result. Each row is 24 fresh JVMs, 4 at a time, on Linux x86_64. A JVM counts as broken when a valid manifest failed to parse; every broken JVM failed with invalid header field (line 1).
| Java | Options | Broken JVMs |
|---|---|---|
| Oracle GraalVM 25.0.4 | none | 0 of 24, and 0 of 24 again |
| Oracle GraalVM 25.0.4 | -XX:StartFlightRecording | 18 of 24, and 21 of 24 again |
| Oracle GraalVM 25.0.4 | -XX:StartFlightRecording -Djdk.graal. | 0 of 24, and 0 of 24 again |
| Oracle GraalVM 25.0.4 | -XX:StartFlightRecording -XX:-UseJVMCICompiler | 0 of 24 |
| Oracle GraalVM 25.0.4 | -XX:StartFlightRecording -Djdk.graal. | 18 of 24 |
| Oracle GraalVM 25.0.3 | none, and -XX:StartFlightRecording | 0 of 48 each |
| GraalVM Community Edition 25.0.4.1.1 | none, and -XX:StartFlightRecording | 0 of 24 each |
| Eclipse Temurin 25.0.5 | none, and -XX:StartFlightRecording | 0 of 24 each |
The bug is timing-dependent, which is why we ran so many JVMs. The 25.0.3 row does not mean 25.0.3 is safe: the second report measured broken JVMs on 25.0.2 (with a larger class path) and on 25.0.4, the releases either side of it.
Where the fix stands
- oracle/graal#14395, September 2026: a
javacbuild on Oracle GraalVM 25.1.3 (on JDK 25.0.3), AMD64, that failed now and then while reading a dependency jar's manifest. The reporter traced it to a compiler phase that removes loops it wrongly treats as empty. The fix was merged into the compiler's main branch on 16 September 2026. - oracle/graal#14797, 28 October 2026: the same failure in production on aarch64, as random
NoClassDefFoundErrorandServiceat startup. It was closed on 29 October as a duplicate of #14395. A maintainer wrote that the fix "hasn't been backported to the 25.0.x series yet" and: "I believe the backport should make it into 25.0.6, planned for January 19, 2027."Configuration Error
So the fix is expected in Oracle GraalVM 25.0.6, which the maintainer says is planned for 19 January 2027. That is a plan, not a promise. On 31 October 2026 the current Oracle GraalVM 25 download is 25.0.4. When 25.0.6 is out, check its release notes for the fix before you remove the flag.
What we tested
- Oracle GraalVM for JDK 25.0.4 and 25.0.3 for Linux x64, unmodified, from download.oracle.com (25.0.4
graalvm-jdk-25.0.4_, sha256linux-x64_ bin.tar.gz 76007c309f821aaf435bce63162ea0395587fc77350801c81643fe7feea37276). GraalVM Community Edition 25.0.4.1.1 and Eclipse Temurin 25.0.5+8 as controls. Each JVM ran in a container with no network, 4 CPUs, 4 JVMs at a time. - The test program and jar from oracle/graal#14797, with
ManifestLoop 2000, unchanged. JAVA_TOOL_OPTIONS=on 25.0.4: plain-Djdk.graal. Vectorization= false javaandjavac(which runs the compiler inside its own JVM) both saw the option set, and Maven 3.9.11's JVM picked it up (mvn -vprinted thePicked upline and exited 0). Everyjava -versionshown on this page, with the flag, with the misspelt flag and withRemoveEmptyLoops.- Not tested: aarch64 (the second report found the same flag stopped it there: 0 of 200 JVMs across aarch64 and AMD64), macOS and Windows, Gradle,
native-imagebuilds,MAVEN_OPTSand.mvn/jvm.config, GitHub Actions runners and Oracle's container images (the workflow and Dockerfile lines above set the same variable but we did not run them), Compose and Kubernetes (that a value set at container start replaces the image's comes from the Docker and Kubernetes documentation, and from our owndocker run -echeck with a Temurin image), and the speed cost of the flag.
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.