Describe the Issue
Two failures in findLeastCommonAncestor, in the two halves of a native image built
with runtime class loading and a runtime JIT (-H:+RuntimeClassLoading,
-H:+GraalJITCompileAtRuntime). Both are internal invariant violations rather than
diagnostics about the application's bytecode, and both occur while computing a
common supertype for a class hierarchy that is partly AOT-analysed and partly loaded
at run time. I believe they are related; they may need separate fixes.
1. Verifier — NullPointerException in InterpreterResolvedObjectType.findLeastCommonAncestor,
reached from ReferenceOperand.mergeWith while merging stack frames at a branch
target. Current, and reproducible in context.
2. Runtime JIT — ClassCastException between the two ResolvedJavaType
implementations. SubstrateType.findLeastCommonAncestor calls
RistrettoType.isAssignableFrom, which casts its argument to RistrettoType and
receives a SubstrateType. Observed on a slightly earlier build of the same image;
since masked because (1) now aborts earlier.
(2) looks actionable by inspection even without a reproducer: a SubstrateType
reaching a method that unconditionally casts to RistrettoType is a type confusion
between sibling implementations, visible at SubstrateType.java:310 and
RistrettoType.java:120.
GraalVM Version
Image runtime:
java version "25.0.4.1" 2026-08-18 LTS
Java Crema+Ristretto 64-Bit Server VM Oracle GraalVM 25.3.4.1-dev+0.1 (build 25.0.4.1+0-LTS-jvmci-25.3-b21, mixed mode, sharing)
Substrate VM Oracle GraalVM 25.3.4.1-dev+0.1 (build 2026-08-18 LTS, serial gc, compressed references)
Builder: Oracle GraalVM 25.0.4.1+0-LTS, svm 25.0.4.1+0-LTS.
This is a development build of 25.3, not a published release, so I cannot tick the
"tried the latest release" box honestly — if these paths have changed since, please
say and I will re-test.
Operating System and Version
macOS 26.5 (build 25F71, Darwin 25.5.0), arm64.
Run Command
The image is an application launcher; the failing workload is Apache Maven 3.9.16
executing a build inside it. Relevant build-time flags:
-H:+RuntimeClassLoading
-H:+GraalJITCompileAtRuntime
-H:+ParseRuntimeOptions
-H:+UnlockExperimentalVMOptions
--link-at-build-time
Serial GC, compressed references, debug-profile image.
Expected Behavior
Verifying and JIT-compiling ordinary third-party library bytecode succeeds, as it
does on the equivalent HotSpot JDK 25 with the same inputs.
Actual Behavior
1. Verifier NPE
The class under verification is com.puppycrawl.tools.checkstyle.Checker
(Checkstyle 12.3.1). The process prints this and dies:
Fatal error: Unexpected host exception reached the interpreter: java.lang.NullPointerException: null
at com.oracle.svm.interpreter.metadata.InterpreterResolvedObjectType.findLeastCommonAncestor(InterpreterResolvedObjectType.java:720)
at com.oracle.svm.interpreter.metadata.InterpreterResolvedObjectType.findLeastCommonAncestor(InterpreterResolvedObjectType.java:73)
at com.oracle.svm.espresso.shared.verifier.ReferenceOperand.mergeWith(Operand.java:342)
at com.oracle.svm.espresso.shared.verifier.MethodVerifier.mergeFrames(MethodVerifier.java:2434)
at com.oracle.svm.espresso.shared.verifier.MethodVerifier.branch(MethodVerifier.java:1106)
at com.oracle.svm.espresso.shared.verifier.MethodVerifier.verify(MethodVerifier.java:1520)
at com.oracle.svm.espresso.shared.verifier.MethodVerifier.verifySafe(MethodVerifier.java:1224)
at com.oracle.svm.espresso.shared.verifier.MethodVerifier.startVerify(MethodVerifier.java:1182)
at com.oracle.svm.espresso.shared.verifier.MethodVerifier.processQueue(MethodVerifier.java:1002)
at com.oracle.svm.espresso.shared.verifier.MethodVerifier.verifyReachableCode(MethodVerifier.java:1012)
at com.oracle.svm.espresso.shared.verifier.Verifier.verify(Verifier.java:51)
at com.oracle.svm.interpreter.CremaVerifier.verify(CremaVerifier.java:58)
at com.oracle.svm.interpreter.CremaVerifier.verifyClass(CremaVerifier.java:51)
at com.puppycrawl.tools.checkstyle.Checker.<init>(Checker.java:144)
Two secondary observations:
- Since the merge is of two reference operands at a branch target, the null looks
like a type that could not be resolved during the merge rather than anything
specific to this class.
- The message says
Fatal error, but it appears again later in the same log, so
execution continues past a failure the runtime has declared fatal. That may be a
separate defect in the fatal-error path.
2. Runtime JIT type confusion
Systemic Graal compilation failure detected: 5 of 236 (2%) of compilations failed during last 43 ms
[max rate set by SystemicCompilationFailureRate is 1%]
Current failure: java.lang.ClassCastException:
com.oracle.svm.graal.meta.SubstrateType cannot be cast to com.oracle.svm.interpreter.ristretto.meta.RistrettoType
at com.oracle.svm.interpreter.ristretto.meta.RistrettoType.isAssignableFrom(RistrettoType.java:120)
at com.oracle.svm.graal.meta.SubstrateType.findLeastCommonAncestor(SubstrateType.java:310)
at jdk.graal.compiler.core.common.type.AbstractObjectStamp.meetTypes(AbstractObjectStamp.java:316)
at jdk.graal.compiler.core.common.type.AbstractObjectStamp.meet(AbstractObjectStamp.java:181)
at jdk.graal.compiler.nodes.type.StampTool.meetOrNull(StampTool.java:69)
at jdk.graal.compiler.nodes.ValuePhiNode.inferStamp(ValuePhiNode.java:92)
at jdk.graal.compiler.phases.common.CanonicalizerPhase.tryInferStamp(CanonicalizerPhase.java:888)
at jdk.graal.compiler.phases.common.CanonicalizerPhase.processNode(CanonicalizerPhase.java:621)
at jdk.graal.compiler.phases.common.IncrementalCanonicalizerPhase.run(IncrementalCanonicalizerPhase.java:77)
at jdk.graal.compiler.phases.common.LoweringPhase.lower(LoweringPhase.java:330)
Enough of these tripped the systemic-failure detector that the VM aborted with
exit 134 and no application output.
A third variant tripped the same detector on that build, included only as a data
point since it is a different (missing-feature) case:
Current failure: com.oracle.svm.core.jdk.UnsupportedFeatureError:
Fast ArrayCopy on byte, uninit false, killing INIT_LOCATION not supported yet.
Steps to Reproduce
I do not have a minimal reproducer, and I would rather say so than send you a
guess. What I have:
- Build an application native image with
-H:+RuntimeClassLoading and
-H:+GraalJITCompileAtRuntime.
- Run Apache Maven 3.9.16 inside it against a project whose build invokes
maven-checkstyle-plugin 3.6.0 with Checkstyle 12.3.1.
- The verifier NPE above occurs during the checkstyle phase, deterministically —
four consecutive runs, identical stack.
Reductions I tried that do not reproduce it, which may narrow where to look:
Class.forName("com.puppycrawl.tools.checkstyle.Checker", false, loader) followed
by getDeclaredConstructors(), with Checkstyle and its dependencies on the class
path: succeeds.
- Instantiating it —
Class.forName(...).getDeclaredConstructor().newInstance():
also succeeds.
So verifying Checker.<init> in isolation is fine, and the failure appears to need
the surrounding classloader environment — a frame merge in which one of the operand
types is not resolvable at that moment. That is consistent with the null coming from
a failed type resolution inside the merge rather than from the class's own bytecode.
I am happy to instrument a build and collect more, given a pointer to what would be
most useful — the operand pair being merged at Operand.java:342 seems the obvious
candidate.
Additional Context
Both failures are type-meet operations over a hierarchy the runtime cannot fully
resolve, in the interpreter's metadata and in the JIT's respectively, which is why
they are filed together. If you would prefer them split, say so and I will.
Describe the Issue
Two failures in
findLeastCommonAncestor, in the two halves of a native image builtwith runtime class loading and a runtime JIT (
-H:+RuntimeClassLoading,-H:+GraalJITCompileAtRuntime). Both are internal invariant violations rather thandiagnostics about the application's bytecode, and both occur while computing a
common supertype for a class hierarchy that is partly AOT-analysed and partly loaded
at run time. I believe they are related; they may need separate fixes.
1. Verifier —
NullPointerExceptioninInterpreterResolvedObjectType.findLeastCommonAncestor,reached from
ReferenceOperand.mergeWithwhile merging stack frames at a branchtarget. Current, and reproducible in context.
2. Runtime JIT —
ClassCastExceptionbetween the twoResolvedJavaTypeimplementations.
SubstrateType.findLeastCommonAncestorcallsRistrettoType.isAssignableFrom, which casts its argument toRistrettoTypeandreceives a
SubstrateType. Observed on a slightly earlier build of the same image;since masked because (1) now aborts earlier.
(2) looks actionable by inspection even without a reproducer: a
SubstrateTypereaching a method that unconditionally casts to
RistrettoTypeis a type confusionbetween sibling implementations, visible at
SubstrateType.java:310andRistrettoType.java:120.GraalVM Version
Image runtime:
Builder:
Oracle GraalVM 25.0.4.1+0-LTS,svm 25.0.4.1+0-LTS.This is a development build of 25.3, not a published release, so I cannot tick the
"tried the latest release" box honestly — if these paths have changed since, please
say and I will re-test.
Operating System and Version
macOS 26.5 (build 25F71, Darwin 25.5.0),
arm64.Run Command
The image is an application launcher; the failing workload is Apache Maven 3.9.16
executing a build inside it. Relevant build-time flags:
Serial GC, compressed references, debug-profile image.
Expected Behavior
Verifying and JIT-compiling ordinary third-party library bytecode succeeds, as it
does on the equivalent HotSpot JDK 25 with the same inputs.
Actual Behavior
1. Verifier NPE
The class under verification is
com.puppycrawl.tools.checkstyle.Checker(Checkstyle 12.3.1). The process prints this and dies:
Two secondary observations:
like a type that could not be resolved during the merge rather than anything
specific to this class.
Fatal error, but it appears again later in the same log, soexecution continues past a failure the runtime has declared fatal. That may be a
separate defect in the fatal-error path.
2. Runtime JIT type confusion
Enough of these tripped the systemic-failure detector that the VM aborted with
exit 134 and no application output.
A third variant tripped the same detector on that build, included only as a data
point since it is a different (missing-feature) case:
Steps to Reproduce
I do not have a minimal reproducer, and I would rather say so than send you a
guess. What I have:
-H:+RuntimeClassLoadingand-H:+GraalJITCompileAtRuntime.maven-checkstyle-plugin3.6.0 with Checkstyle 12.3.1.four consecutive runs, identical stack.
Reductions I tried that do not reproduce it, which may narrow where to look:
Class.forName("com.puppycrawl.tools.checkstyle.Checker", false, loader)followedby
getDeclaredConstructors(), with Checkstyle and its dependencies on the classpath: succeeds.
Class.forName(...).getDeclaredConstructor().newInstance():also succeeds.
So verifying
Checker.<init>in isolation is fine, and the failure appears to needthe surrounding classloader environment — a frame merge in which one of the operand
types is not resolvable at that moment. That is consistent with the null coming from
a failed type resolution inside the merge rather than from the class's own bytecode.
I am happy to instrument a build and collect more, given a pointer to what would be
most useful — the operand pair being merged at
Operand.java:342seems the obviouscandidate.
Additional Context
Both failures are type-meet operations over a hierarchy the runtime cannot fully
resolve, in the interpreter's metadata and in the JIT's respectively, which is why
they are filed together. If you would prefer them split, say so and I will.