elastic/elasticsearch · error · IllegalStateException

no execute method found

Error message

no execute method found

What it means

After iterating all non-default methods of the context interface, ScriptClassInfo asserts that an execute method was found. If none is present, this IllegalStateException is thrown. Every Painless-implementable interface must declare a single non-default method literally named execute.

Source

Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java:99

                                + "type ["
                                + componentType.getName()
                                + "]. Painless can only support getters with return types that are "
                                + "whitelisted."
                        )
                    );

                    getMethods.add(
                        new org.objectweb.asm.commons.Method(
                            m.getName(),
                            MethodType.methodType(m.getReturnType()).toMethodDescriptorString()
                        )
                    );

                }
        }

        if (executeMethod == null) {
            throw new IllegalStateException("no execute method found");
        }
        ArrayList<FunctionTable.LocalFunction> converters = new ArrayList<>();
        FunctionTable.LocalFunction defConverter = null;
        for (java.lang.reflect.Method m : baseClass.getMethods()) {
            if (m.getName().startsWith("convertFrom")
                && m.getParameterTypes().length == 1
                && m.getReturnType() == returnType
                && Modifier.isStatic(m.getModifiers())) {

                if (m.getName().equals("convertFromDef")) {
                    if (m.getParameterTypes()[0] != Object.class) {
                        throw new IllegalStateException(
                            "convertFromDef must take a single Object as an argument, " + "not [" + m.getParameterTypes()[0] + "]"
                        );
                    }
                    defConverter = new FunctionTable.LocalFunction(
                        m.getName(),
                        m.getReturnType(),

View on GitHub (pinned to db6a809a66)

Solutions

  1. Add a non-default method named 'execute' to the interface returning a whitelisted type.
  2. If the method exists but is marked default, remove the default keyword so it becomes abstract.
  3. Confirm the interface is the one actually passed as baseClass to ScriptClassInfo.

Example fix

// before
public interface MyScript {
    default double execute() { return 0; } // skipped -> 1342
}
// after
public interface MyScript {
    double execute();
}
Defensive patterns

Strategy: validation

Validate before calling

void assertHasExecute(Class<?> iface) {
    boolean has = java.util.Arrays.stream(iface.getMethods())
        .anyMatch(m -> !m.isDefault() && m.getName().equals("execute"));
    if (!has) throw new IllegalStateException("interface needs a non-default execute method");
}

Try / catch

try {
    new ScriptClassInfo(lookup, MyScript.class);
} catch (IllegalStateException e) {
    if (e.getMessage().equals("no execute method found")) {
        fail("Add a non-default 'execute' method to " + MyScript.class.getName());
    }
    throw e;
}

Prevention

When it happens

Trigger: Registering a custom ScriptContext whose interface has no method named execute (e.g. it was named run, apply, or compute), or whose only execute is a default method (default methods are skipped by the loop at line 55-56).

Common situations: Renaming execute to a different method name during a refactor; implementing a functional interface from another framework verbatim; making execute a default method by accident.

Related errors


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