oracle/graal · error · UnsupportedClassVersionError
Unsupported class file version: %s.%s
Error message
Unsupported class file version: %s.%s
What it means
Classfile is the minimal class-file parser used by ClassfileBytecodeProvider to read snippet/replacement classes. After reading magic it reads minor/major version and rejects the file with UnsupportedClassVersionError if major is below MAJOR_VERSION_JAVA_MIN (the oldest class file version Graal will parse).
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/classfile/Classfile.java:77
// Graal change when updating to a newer JDK.
/**
* Creates a {@link Classfile} by parsing the class file bytes for {@code type} loadable from
* {@code context}.
*
* @throws NoClassDefFoundError if there is an IO error while parsing the class file
*/
public Classfile(ResolvedJavaType type, DataInputStream stream, ClassfileBytecodeProvider context) throws IOException {
this.type = type;
// magic
int magic = stream.readInt();
assert magic == MAGIC : Assertions.errorMessage(magic);
int minor = stream.readUnsignedShort();
int major = stream.readUnsignedShort();
if (major < MAJOR_VERSION_JAVA_MIN) {
throw new UnsupportedClassVersionError("Unsupported class file version: " + major + "." + minor);
}
try {
ClassfileConstantPool cp = new ClassfileConstantPool(stream, context);
// access_flags, this_class, super_class
skipFully(stream, 6);
// interfaces
skipFully(stream, stream.readUnsignedShort() * 2);
// fields
skipFields(stream);
// methods
codeAttributes = readMethods(stream, cp);
// attributesView on GitHub (pinned to a66e9ccd1d)
Solutions
- Recompile the offending classes with a supported target (raise javac --release/-target to at least the minimum Graal supports).
- Upgrade the dependency that ships the ancient class files.
- Verify the class file with javap -v and check the 'major version' line; if unreadable, replace the artifact (bad download/transfer).
Example fix
// before javac --release 7 Snippet.java // after javac --release 17 Snippet.java
Defensive patterns
Strategy: try-catch
Validate before calling
// Cheap pre-check of a class file's version before parsing
static boolean versionSupported(java.nio.file.Path classFile) throws java.io.IOException {
try (var in = new java.io.DataInputStream(java.nio.file.Files.newInputStream(classFile))) {
in.readInt(); // magic
int minor = in.readUnsignedShort();
int major = in.readUnsignedShort();
return major >= 45 + 8; // use the same minimum your provider enforces
}
} Try / catch
try {
Classfile cf = new Classfile(type, stream, provider);
} catch (UnsupportedClassVersionError e) {
// Report which class is too old and rebuild/upgrade it; do not retry with the same bytes
throw new IllegalStateException("Class file too old for Graal parsing: " + type.toJavaName(), e);
} Prevention
- Pin --release to a currently supported Java version in all build configs that feed snippet classes.
- Fail the build when a dependency jar contains class files below the supported major version (e.g. with a maven/gradle enforcer rule).
When it happens
Trigger: Parsing a class file compiled with an ancient -target/--release value below the supported minimum, or a stream whose version fields read low because the data is truncated/corrupt (though the magic assert must have matched in checked builds).
Common situations: Old third-party jars compiled for very old Java targets on the snippet path; builds that pin --release to a too-low value; truncated or corrupted class files in a jar.
Related errors
- expected phase_name=filter pair in: {}
- {file}:{line}: {cause}
- Directed inlining rule must have non-empty caller and callee
- Directed inlining rule has an empty {componentName} filter o
- Directed inlining rule receiver type filter must name exactl
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/953ad63438fb9a3a.
Report an issue: GitHub.