elastic/elasticsearch · error · LambdaConversionException

lambda expects return type [{}], but found return type [void

Error message

lambda expects return type [{}], but found return type [void]

What it means

LambdaBootstrap.validateTypes throws this LambdaConversionException at link time when a lambda's functional interface declares a non-void return type but the delegate method (the lambda body or referenced method) returns void. The JVM's lambda metafactory requires that the SAM method and the implementation agree on return type; a value-returning interface cannot delegate to a void method because there would be no value to return. Painless checks this explicitly to give a clear message before the metafactory fails.

Source

Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/LambdaBootstrap.java:359

        endLambdaClass(cw);

        Class<?> lambdaClass = createLambdaClass(loader, cw, lambdaClassType);
        if (captures.length > 0) {
            return createCaptureCallSite(lookup, factoryMethodType, lambdaClass);
        } else {
            return createNoCaptureCallSite(factoryMethodType, lambdaClass);
        }
    }

    /**
     * Validates some conversions at link time.  Currently, only ensures that the lambda method
     * with a return value cannot delegate to a delegate method with no return type.
     */
    private static void validateTypes(MethodType interfaceMethodType, MethodType delegateMethodType) throws LambdaConversionException {

        if (interfaceMethodType.returnType() != void.class && delegateMethodType.returnType() == void.class) {
            throw new LambdaConversionException(
                "lambda expects return type [" + interfaceMethodType.returnType() + "], but found return type [void]"
            );
        }
    }

    /**
     * Creates the {@link ClassWriter} to be used for the lambda class generation.
     */
    private static ClassWriter beginLambdaClass(String lambdaClassName, Class<?> lambdaInterface) {
        String baseClass = Type.getInternalName(Object.class);
        int modifiers = ACC_PUBLIC | ACC_SUPER | ACC_FINAL | ACC_SYNTHETIC;

        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        cw.visit(CLASS_VERSION, modifiers, lambdaClassName, null, baseClass, new String[] { Type.getInternalName(lambdaInterface) });

        return cw;
    }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Ensure the lambda body returns a value matching the interface's return type.
  2. Switch to a void-returning functional interface (e.g. Runnable or Consumer) if the body intentionally has no return value.
  3. If using a method reference, pick a method whose return type matches the interface's SAM return type.

Example fix

// before
Supplier<String> s = () -> { doc['x'].value; };  // body returns void (statement)
// after
Supplier<String> s = () -> doc['x'].value;  // expression returns the value
Defensive patterns

Strategy: validation

Validate before calling

// Match the lambda body's return type to the interface SAM return type:
// // Supplier<String> s = () -> 'value';  // returns String, matches Supplier.get()
// // Runnable r = () -> { println('x'); };  // void body, matches Runnable.run()

Prevention

When it happens

Trigger: Writing a lambda or method reference assigned to a functional interface whose method returns a value, but the body or referenced method returns void: 'Supplier<String> s = () -> { System.out.println('hi'); };' — the lambda body returns nothing but Supplier.get() must return a String.

Common situations: Mismatching a lambda body that performs a side effect (no return) with a value-returning functional interface like Function, Supplier, or Predicate. Method references to void-returning methods (e.g. System.out::println) assigned to Function/Supplier types.

Related errors


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