elastic/elasticsearch · error · IllegalArgumentException
cannot convert function reference [%s::%s] to a non-function
Error message
cannot convert function reference [%s::%s] to a non-functional interface [%s]
What it means
FunctionRef.create throws this IllegalArgumentException at compile time when a Painless method-reference expression (Type::method) targets a class that is not a functional interface. Painless method references can only be converted to types that declare exactly one abstract method (a SAM type). The compiler calls lookupFunctionalInterfacePainlessMethod; if it returns null, the target has zero or multiple abstract methods and the reference cannot be bound.
Source
Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java:78
String methodName,
int numberOfCaptures,
Map<String, Object> constants,
boolean needsScriptInstance
) {
Objects.requireNonNull(painlessLookup);
Objects.requireNonNull(targetClass);
Objects.requireNonNull(typeName);
Objects.requireNonNull(methodName);
String targetClassName = PainlessLookupUtility.typeToCanonicalTypeName(targetClass);
PainlessMethod interfaceMethod;
try {
interfaceMethod = painlessLookup.lookupFunctionalInterfacePainlessMethod(targetClass);
if (interfaceMethod == null) {
throw new IllegalArgumentException(
Strings.format(
"cannot convert function reference [%s::%s] to a non-functional interface [%s]",
typeName,
methodName,
targetClassName
)
);
}
String interfaceMethodName = interfaceMethod.javaMethod().getName();
MethodType interfaceMethodType = interfaceMethod.methodType().dropParameterTypes(0, 1);
String delegateClassName;
boolean isDelegateInterface;
boolean isDelegateAugmented;
int delegateInvokeType;
String delegateMethodName;
MethodType delegateMethodType;
Object[] delegateInjections;View on GitHub (pinned to db6a809a66)
Solutions
- Ensure the target type is a single-abstract-method interface (e.g. java.util.function.Function, Consumer, Predicate) that is whitelisted in Painless.
- Replace the method reference with an explicit lambda that implements the interface.
- Check the Painless allowlist for the interface; if it is missing, the method reference will not compile.
Example fix
// before SomeClass ref = String::length; // SomeClass is not a functional interface // after Function<String, Integer> ref = String::length;
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the target type is a single-method interface before using a method reference: // // java.util.function.Function, Consumer, Predicate, Supplier are valid functional interfaces
Prevention
- Only assign method references to functional interfaces (single abstract method).
- Check the Painless allowlist for the interface.
- Prefer explicit lambdas when unsure about functional interface status.
When it happens
Trigger: Writing a Painless method reference where the target type is a marker interface, an abstract class with multiple methods, or a concrete class: 'Consumer c = List::size;' where List is not whitelisted as a functional interface, or assigning to a type Painless does not recognize as functional.
Common situations: Using method references with interfaces that Painless's whitelist does not mark as functional. Attempting to use a Java interface not allowed in scripts. Confusing a method reference target with a regular class type.
Related errors
- function reference [this::%s] matching [%s, %s/%d] not found
- function reference [%s::%s/%d] matching [%s, %s/%d] not foun
- cannot use a static method as a function reference [%s::%s/%
- Cannot apply operator [{}] to type [{}]
- Cannot apply operator [{}] to types [{}] and [{}]
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/66a0ab01dc4cc668.
Report an issue: GitHub.