{"record":{"id":"7193ea291037d264","repo":"elastic/elasticsearch","slug":"proxy-fallback-only-supports-instance-method-refer","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"libs/entitlement/src/main/java/org/elasticsearch/entitlement/rules/ClassMethodBuilder.java","lineNumber":1165,"sourceCode":"\n        Object[] callArgs = new Object[1 + args.length];\n        callArgs[0] = proxy;\n        for (int i = 0; i < args.length; i++) {\n            callArgs[1 + i] = TypeUtils.defaultValueFor(args[i]);\n        }\n\n        if (ref instanceof VarargCallAdapter<?> adapter) {\n            adapter.asVarargCall().call(callArgs);\n        } else {\n            Class<?>[] paramTypes = new Class<?>[1 + args.length];\n            paramTypes[0] = clazz;\n            System.arraycopy(args, 0, paramTypes, 1, args.length);\n            Method callMethod = ref.getClass().getMethod(\"call\", paramTypes);\n            callMethod.invoke(ref, callArgs);\n        }\n\n        if (holder.recordedMethod == null) {\n            throw new IllegalStateException(\n                \"Proxy fallback only supports instance method references; no method was invoked on the proxy for \"\n                    + clazz.getName()\n                    + \". If this is a static method reference, resolution must use SerializedLambda.\"\n            );\n        }\n        return methodKeyFromMethod(holder.recordedMethod);\n    }\n\n    private static MethodKey methodKeyFromMethod(Method method) {\n        String className = method.getDeclaringClass().getName().replace(\".\", \"/\");\n        String methodName = method.getName();\n        List<String> parameterTypes = Arrays.stream(method.getParameterTypes()).map(TypeUtils::getParameterTypeName).toList();\n        return new MethodKey(className, methodName, parameterTypes);\n    }\n\n    private static void assertImplementationClass(Class<?> clazz, String implClassName) throws ClassNotFoundException {\n        Class<?> implClass = Class.forName(implClassName.replace(\"/\", \".\"));\n        if (implClass.isAssignableFrom(clazz) == false) {","sourceCodeStart":1147,"sourceCodeEnd":1183,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/entitlement/src/main/java/org/elasticsearch/entitlement/rules/ClassMethodBuilder.java#L1147-L1183","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use an instance method reference instead of a static one so the proxy receives the call.","Fix the SerializedLambda path so static references are resolved there (make the functional interface Serializable) and never reach the proxy fallback.","Refactor the rule to use the explicit method-name overload of calling() if available."],"exampleFix":"// before: static method reference reaches proxy fallback\npolicy.calling(MyInterface::staticHelper);\n\n// after: instance reference, or serializable so SerializedLambda resolves it\npolicy.calling(concreteInstance::helper);\n// or make the interface Serializable so SerializedLambda handles static refs","handlingStrategy":"validation","validationCode":"// Detect static method references before they reach the proxy path\n// Static refs cannot be resolved by proxy invocation; require Serializable interface\nif (isStaticMethodReference(ref) && !java.io.Serializable.class.isAssignableFrom(ref.getClass())) {\n  throw new IllegalArgumentException(\"Static method reference requires Serializable functional interface\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never pass static method references to interface-typed calling() rules.","Prefer instance references or explicit method-name overloads."],"tags":["entitlement","method-reference","proxy","reflection","policy"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}