elastic/elasticsearch · error · IllegalStateException

Proxy fallback only supports instance method references; no

Error message

Proxy fallback only supports instance method references; no method was invoked on the proxy for {}. If this is a static method reference, resolution must use SerializedLambda.

What it means

Thrown by the proxy-fallback path in ClassMethodBuilder when invoking the method reference against a recording proxy did not capture any method (holder.recordedMethod is null). The proxy fallback only works for instance method references because it needs the proxy to receive a method call; a static method reference invokes nothing on the proxy, so nothing is recorded. The message directs the user to SerializedLambda for static references.

Source

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

        Object[] callArgs = new Object[1 + args.length];
        callArgs[0] = proxy;
        for (int i = 0; i < args.length; i++) {
            callArgs[1 + i] = TypeUtils.defaultValueFor(args[i]);
        }

        if (ref instanceof VarargCallAdapter<?> adapter) {
            adapter.asVarargCall().call(callArgs);
        } else {
            Class<?>[] paramTypes = new Class<?>[1 + args.length];
            paramTypes[0] = clazz;
            System.arraycopy(args, 0, paramTypes, 1, args.length);
            Method callMethod = ref.getClass().getMethod("call", paramTypes);
            callMethod.invoke(ref, callArgs);
        }

        if (holder.recordedMethod == null) {
            throw new IllegalStateException(
                "Proxy fallback only supports instance method references; no method was invoked on the proxy for "
                    + clazz.getName()
                    + ". If this is a static method reference, resolution must use SerializedLambda."
            );
        }
        return methodKeyFromMethod(holder.recordedMethod);
    }

    private static MethodKey methodKeyFromMethod(Method method) {
        String className = method.getDeclaringClass().getName().replace(".", "/");
        String methodName = method.getName();
        List<String> parameterTypes = Arrays.stream(method.getParameterTypes()).map(TypeUtils::getParameterTypeName).toList();
        return new MethodKey(className, methodName, parameterTypes);
    }

    private static void assertImplementationClass(Class<?> clazz, String implClassName) throws ClassNotFoundException {
        Class<?> implClass = Class.forName(implClassName.replace("/", "."));
        if (implClass.isAssignableFrom(clazz) == false) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Use an instance method reference instead of a static one so the proxy receives the call.
  2. Fix the SerializedLambda path so static references are resolved there (make the functional interface Serializable) and never reach the proxy fallback.
  3. Refactor the rule to use the explicit method-name overload of calling() if available.

Example fix

// before: static method reference reaches proxy fallback
policy.calling(MyInterface::staticHelper);

// after: instance reference, or serializable so SerializedLambda resolves it
policy.calling(concreteInstance::helper);
// or make the interface Serializable so SerializedLambda handles static refs
Defensive patterns

Strategy: validation

Validate before calling

// Detect static method references before they reach the proxy path
// Static refs cannot be resolved by proxy invocation; require Serializable interface
if (isStaticMethodReference(ref) && !java.io.Serializable.class.isAssignableFrom(ref.getClass())) {
  throw new IllegalArgumentException("Static method reference requires Serializable functional interface");
}

Prevention

When it happens

Trigger: resolveMethodReferenceViaProxy runs: a dynamic proxy for the interface is created, the reference's 'call' is invoked with the proxy as the receiver, but the InvocationHandler never records a method (recordedMethod stays null). This happens for static method references and for references that short-circuit before invoking on the receiver.

Common situations: Passing a static method reference (e.g. MyClass::staticMethod) to calling() where the resolver falls into the proxy branch because SerializedLambda failed; a lambda that does not invoke the proxied method in its body.

Related errors


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