elastic/elasticsearch · critical · IllegalStateException
Unexpected class file version ${rawVersion} for ${cn.name} (
Error message
Unexpected class file version ${rawVersion} for ${cn.name} (expected ${V21} / JDK 21) What it means
Thrown as IllegalStateException by checkJava21(ClassNode) when (cn.version & 0xFFFF) != V21 (65). Before stripping the preview flag and @PreviewFeature annotations from a java.lang.foreign class, the worker asserts the input class file is exactly major version 65 (JDK 21). A different version means the jrt:/ image is not a JDK 21 image, and the stub-generation logic (which assumes preview semantics) would produce an incorrect JAR.
Source
Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ExtractForeignApiTask.java:260
cn.innerClasses.removeIf(ic -> (ic.access & Opcodes.ACC_PUBLIC) == 0);
ClassWriter writer = new ClassWriter(0);
cn.accept(writer);
return writer.toByteArray();
}
private static List<AnnotationNode> stripPreviewAnnotations(List<AnnotationNode> anns) {
if (anns == null) {
return null;
}
anns.removeIf(a -> a.desc.equals(PREVIEW_FEATURE_DESCRIPTOR));
return anns.isEmpty() ? null : anns;
}
private static void checkJava21(ClassNode cn) {
int rawVersion = cn.version & 0xFFFF;
if (rawVersion != V21) {
throw new IllegalStateException(
"Unexpected class file version " + rawVersion + " for " + cn.name + " (expected " + V21 + " / JDK 21)"
);
}
}
}
}
View on GitHub (pinned to db6a809a66)
Solutions
- Confirm the JDK 21 in use is a stable GA release (Temurin/Zulu/Corretto 21.x GA) — re-point JAVA_HOME or the toolchain to a GA JDK 21.
- Inspect the offending class with javap -v against the JDK image to see its actual major version and confirm whether the image is corrupted.
- If the project upgraded the foreign stub expectations, update V21 handling in ExtractForeignApiTask to match the new target version.
- Reinstall the JDK 21 installation if a custom/patched module replaced java.base.
Example fix
// before: EA JDK 21 with foreign classes at version 66
// throws: Unexpected class file version 66 for java/lang/foreign/MemorySegment
// after: switch toolchain to a GA JDK 21 where foreign classes are version 65
javaToolchainService.launcherFor {
it.languageVersion.set(JavaLanguageVersion.of(21))
it.vendor.set(JvmVendor.ADOPTIUM)
}.let { task.getJdk21Launcher().set(it) } Defensive patterns
Strategy: validation
Validate before calling
ClassReader reader = new ClassReader(classStream);
int major = (reader.readUnsignedShort(6)) & 0xFFFF; // class file major version offset
if (major != 65 /* V21 */) {
throw new IllegalStateException("Refusing to process non-JDK21 class file (version " + major + ")");
} Prevention
- Use a stable GA JDK 21 (not EA/custom builds) for foreign API stub extraction.
- Reinstall the JDK image if java.base was patched or corrupted.
- Avoid GraalVM/EA builds for this task unless their class file versions match GA.
- Pin the JDK 21 vendor/version in the toolchain spec.
When it happens
Trigger: createStub() (line 205) reads a class from jrt:/modules/java.base/java/lang/foreign, parses it with ASM, and calls checkJava21(cn) at line 209. If the runtime is JDK 21 but the class file's major version isn't 65 — e.g., a backported/custom JDK image, a corrupted module, or an unexpectedly updated JDK where foreign classes shifted versions — the assertion fires.
Common situations: Using an early-access or custom-built JDK 21 where class file versions differ; a JDK image patched with classes from a different version; running against a non-standard distribution (GraalVM, Zulu) where foreign package classes carry a different version tag in EA builds.
Related errors
- Failed to extract foreign API stubs
- ExtractForeignApiTask worker must run on JDK 21 (found JDK $
- TransportVersion.fromName must be called with a non-empty St
- Error patching JAR [%s]: SHA256 digest mismatch (%s). This J
- error patching [%s]: the jar does not contain [%s]
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/780fdbfe411ae48c.
Report an issue: GitHub.