oracle/graal · critical · IllegalStateException

Recording failed due to an exception

Error message

Recording failed due to an exception

What it means

RecordingCompilationProxies replays each recorded compiler-interface call with reflection: invokableMethod().invoke(...). InvocationTargetException is expected and recorded as the method's thrown exception; IllegalAccessException, however, means the reflective call itself could not be made (access check failed) — a setup/infrastructure failure, so it is wrapped in IllegalStateException('Recording failed due to an exception').

Source

Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replaycomp/RecordingCompilationProxies.java:137

            Object receiver = worklist.removeLast();
            CompilerInterfaceDeclarations.Registration registration = declarations.findRegistrationForInstance(receiver);
            for (CompilerInterfaceDeclarations.MethodCallToRecord methodCall : registration.getMethodCallsToRecord(receiver)) {
                OperationRecorder.RecordedOperationKey key = new OperationRecorder.RecordedOperationKey(methodCall.receiver(), methodCall.symbolicMethod(), methodCall.args());
                if (recorder.getRecordedResultOrMarker(key) != SpecialResultMarker.NO_RESULT_MARKER) {
                    // The result of the call is already recorded.
                    continue;
                }
                try {
                    Object result = methodCall.invokableMethod().invoke(methodCall.receiver(), methodCall.args());
                    recorder.recordReturnValue(key, result);
                    // Make sure to record the method calls for the results of this call as well.
                    worklistAdder.proxifyRecursive(result);
                } catch (InvocationTargetException e) {
                    Throwable cause = e.getCause();
                    recorder.recordExceptionThrown(key, cause);
                    worklistAdder.proxifyRecursive(cause);
                } catch (IllegalAccessException e) {
                    throw new IllegalStateException("Recording failed due to an exception", e);
                }
            }
        }
        return recorder.getCurrentRecordedOperations();
    }

    @Override
    public DebugCloseable enterCompilationContext() {
        return recorder.enterCompilationContext();
    }

    @Override
    public DebugCloseable enterSnippetContext() {
        return recorder.enterIgnoredContext();
    }

    @Override
    public Platform targetPlatform() {

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Add the required --add-opens / --add-exports JVM flags so the recorder module can reflectively invoke the implementation classes
  2. Verify invokableMethod() applies setAccessible(true) (or uses a MethodHandles.Lookup with access) for non-public methods
  3. Check the cause chain of the IllegalStateException to see exactly which member failed access, then widen that member's visibility or open its package

Example fix

# before
java -XX:+UnlockExperimentalVMOptions -Dgraal.ReplaySupport=true ...
# after: open the compiler packages to reflection
java --add-opens jdk.internal.vm.compiler/jdk.graal.compiler.hotspot.replaycomp=ALL-UNNAMED ...
Defensive patterns

Strategy: try-catch

Validate before calling

// Before recording, verify reflective access to the implementation method
Method m = recordedCall.invokableMethod();
try {
    m.setAccessible(true);
    m.canAccess(receiver); // returns false if access would fail
} catch (RuntimeException e) {
    throw new IllegalStateException("Access not open for " + m, e);
}

Try / catch

catch (IllegalStateException e) {
    if (e.getCause() instanceof IllegalAccessException iae) {
        // infrastructure problem: add --add-opens for the member's package, then re-run recording
        throw new ReplaySetupException("Reflective access blocked: " + iae.getMessage(), iae);
    }
    throw e;
}

Prevention

When it happens

Trigger: A recorded method's accessibility is blocked at invoke time: the method is non-public and setAccessible failed or was not applied, the receiver is in a module/package not opened to the recorder, or a SecurityManager/JPMS access check rejects the call.

Common situations: Running on a JDK with strong encapsulation where compiler classes are not opened (--add-opens missing); recording interfaces whose implementations moved to non-public classes between versions; security manager policies; custom compiler-interface methods with reduced visibility.

Related errors


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