elastic/elasticsearch · error · IllegalArgumentException
Painless can only implement interfaces that have a single me
Error message
Painless can only implement interfaces that have a single method named [execute] but [{}] has more than one. What it means
ScriptClassInfo scans a script-context interface via reflection and requires exactly one non-default method named 'execute'. If two or more methods named execute are visible on the interface (overloads, or inherited from multiple super-interfaces), the second one triggers this IllegalArgumentException during PainlessLookup/context initialization. The interface name is interpolated into the message.
Source
Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java:63
this.baseClass = baseClass;
// Find the main method and the uses$argName methods
java.lang.reflect.Method executeMethod = null;
List<org.objectweb.asm.commons.Method> needsMethods = new ArrayList<>();
List<org.objectweb.asm.commons.Method> getMethods = new ArrayList<>();
List<Class<?>> getReturns = new ArrayList<>();
Class<?> returnType = null;
for (java.lang.reflect.Method m : baseClass.getMethods()) {
if (m.isDefault()) {
continue;
}
if (m.getName().equals("execute")) {
if (executeMethod == null) {
executeMethod = m;
returnType = m.getReturnType();
} else {
throw new IllegalArgumentException(
"Painless can only implement interfaces that have a single method named [execute] but ["
+ baseClass.getName()
+ "] has more than one."
);
}
} else if (m.getName().startsWith("needs") && m.getReturnType() == boolean.class && m.getParameterTypes().length == 0) {
needsMethods.add(new org.objectweb.asm.commons.Method(m.getName(), NEEDS_PARAMETER_METHOD_TYPE.toMethodDescriptorString()));
} else if (m.getName().startsWith("get")
&& m.getName().equals("getClass") == false
&& Modifier.isStatic(m.getModifiers()) == false) {
getReturns.add(
definitionTypeForClass(
painlessLookup,
m.getReturnType(),
componentType -> "["
+ m.getName()
+ "] has unknown return "
+ "type ["View on GitHub (pinned to db6a809a66)
Solutions
- Ensure the context interface exposes exactly one non-default method named execute.
- Remove or rename the duplicate execute method; if a variant is needed, make it a default method (default methods are skipped by the loop).
- Rebuild and redeploy the plugin/module that registers the context.
Example fix
// before
public interface MyScript {
double execute(Map<String,Object> params);
double execute(); // duplicate -> triggers 1341
}
// after
public interface MyScript {
double execute(Map<String,Object> params);
} Defensive patterns
Strategy: validation
Validate before calling
void assertSingleExecute(Class<?> iface) {
long count = java.util.Arrays.stream(iface.getMethods())
.filter(m -> !m.isDefault() && m.getName().equals("execute"))
.count();
if (count != 1) throw new IllegalStateException("interface must have exactly one execute, found " + count);
} Try / catch
try {
new ScriptClassInfo(lookup, MyScript.class);
} catch (IllegalArgumentException e) {
// message names the offending interface
fail("Invalid script context interface: " + e.getMessage());
} Prevention
- When authoring a custom context, run a reflection unit test asserting exactly one non-default execute.
- Mark convenience overloads as default methods so they are skipped.
- Avoid multiple inheritance of interfaces that both declare execute.
When it happens
Trigger: Defining a custom ScriptContext whose interface declares two overloaded execute(...) methods, or whose interface inherits execute from more than one super-interface, and then registering that context with the Painless engine so ScriptClassInfo is constructed for it.
Common situations: Authoring a custom script context (e.g. for a plugin) and accidentally overloading execute; merging two interfaces that both define execute; refactor that added a convenience execute overload.
Related errors
- no execute method found
- convertFromDef must take a single Object as an argument, not
- [{}#ARGUMENTS] has length [2] but [{}#execute] takes [1] arg
- Painless needs a constant [String[] PARAMETERS] on all inter
- Error trying to read [{}#ARGUMENTS]
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/d9aab488ecc16d22.
Report an issue: GitHub.