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);

            // attributes

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Recompile the offending classes with a supported target (raise javac --release/-target to at least the minimum Graal supports).
  2. Upgrade the dependency that ships the ancient class files.
  3. 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

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


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/953ad63438fb9a3a. Report an issue: GitHub.