elastic/elasticsearch · error · RuntimeException

Error occurred when inspecting class: {}

Error message

Error occurred when inspecting class: {}

What it means

Thrown by ClassMethodBuilder.resolveMethodReference when SerializedLambda resolution fails for a NON-interface class (the proxy-fallback branch only applies to interfaces). The original exception is the cause. This means the method-reference passed to an entitlement rule on a concrete class could not be decoded via the lambda's writeReplace/SerializedLambda mechanism.

Source

Thrown at libs/entitlement/src/main/java/org/elasticsearch/entitlement/rules/ClassMethodBuilder.java:1110

    @SuppressForbidden(reason = "relies on reflection")
    private static MethodKey resolveMethodReference(Class<?> clazz, Object ref, Class<?>... args) {
        try {
            return resolveMethodReferenceViaSerializedLambda(clazz, ref, args);
        } catch (Exception e) {
            if (clazz.isInterface()) {
                try {
                    return resolveMethodReferenceViaProxy(clazz, ref, args);
                } catch (Exception proxyException) {
                    proxyException.addSuppressed(e);
                    throw new RuntimeException(
                        "Error occurred when inspecting class: "
                            + clazz.getName()
                            + "; SerializedLambda resolution failed and proxy fallback failed",
                        proxyException
                    );
                }
            }
            throw new RuntimeException("Error occurred when inspecting class: " + clazz.getName(), e);
        }
    }

    @SuppressForbidden(reason = "relies on reflection")
    private static MethodKey resolveMethodReferenceViaSerializedLambda(Class<?> clazz, Object ref, Class<?>... args) throws Exception {
        Method writeReplace = ref.getClass().getDeclaredMethod("writeReplace");
        writeReplace.setAccessible(true);

        SerializedLambda serialized = (SerializedLambda) writeReplace.invoke(ref);
        String className = serialized.getImplClass();
        String methodName = serialized.getImplMethodName();

        assertImplementationClass(clazz, className);

        return new MethodKey(
            resolveDeclaringClass(clazz, methodName, args).getTypeName().replace(".", "/"),
            methodName,
            Arrays.stream(args).map(TypeUtils::getParameterTypeName).toList()

View on GitHub (pinned to db6a809a66)

Solutions

  1. Make the functional interface the method reference targets extend Serializable so writeReplace is available.
  2. Run with module opens that allow reflective access to the lambda's class (add '--add-opens' if appropriate for the test/tool).
  3. If the reference is not really a lambda, refactor the rule to use an explicit constructor/method overload (e.g. resolveConstructor / validateConstructorExists).
  4. Inspect the cause exception for the specific reflection failure.

Example fix

// before: non-serializable functional interface
policy.calling(MyClass::method).isAllowed(...);

// after: serializable interface
interface MySerFun extends Runnable, Serializable {}
policy.calling((MySerFun) MyClass::method).isAllowed(...);
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure the functional interface is Serializable before building the rule
if (!java.io.Serializable.class.isAssignableFrom(funType)) {
  throw new IllegalArgumentException(funType + " must be Serializable for SerializedLambda resolution");
}

Try / catch

try {
  builder.calling(ref);
} catch (RuntimeException e) {
  if (e.getMessage().startsWith("Error occurred when inspecting class:")) {
    // root cause is in e.getCause(); fix serializability or refactor to explicit method/constructor overloads
  }
  throw e;
}

Prevention

When it happens

Trigger: resolveMethodReferenceViaSerializedLambda throws for a class where clazz.isInterface() is false; the else branch rethrows wrapped with the class name. Typical when the method reference is not a serializable lambda or writeReplace is inaccessible.

Common situations: Passing a non-serializable method reference to calling(); the lambda target type is not Serializable; reflective access to writeReplace is denied by module rules; the reference is actually a reflective Method handle, not a lambda.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/ccf412c715337af3. Report an issue: GitHub.