elastic/elasticsearch · error · IllegalStateException
convertFromDef must take a single Object as an argument, not
Error message
convertFromDef must take a single Object as an argument, not [{}] What it means
When the context interface declares a static method named convertFromDef (the hook Painless uses to convert a 'def' value to the execute return type), ScriptClassInfo requires its single parameter to be exactly java.lang.Object. If the parameter type differs, this IllegalStateException is thrown with the offending parameter type interpolated.
Source
Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java:111
);
}
}
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(),
List.of(m.getParameterTypes()),
true,
true
);
} else {
converters.add(
new FunctionTable.LocalFunction(m.getName(), m.getReturnType(), List.of(m.getParameterTypes()), true, true)
);
}
}
}
this.defConverter = defConverter;View on GitHub (pinned to db6a809a66)
Solutions
- Change the signature of convertFromDef to 'static <ReturnType> convertFromDef(Object value)'.
- If you did not intend def conversion, remove the convertFromDef method entirely (other convertFrom* methods are allowed).
- Rebuild the module/plugin and re-register the context.
Example fix
// before
public interface MyScript {
double execute();
static double convertFromDef(Double v) { return v; } // -> 1343
}
// after
public interface MyScript {
double execute();
static double convertFromDef(Object v) { return ((Number) v).doubleValue(); }
} Defensive patterns
Strategy: validation
Validate before calling
void assertConvertFromDefSignature(Class<?> iface, Class<?> returnType) {
for (java.lang.reflect.Method m : iface.getMethods()) {
if (m.getName().equals("convertFromDef") && java.lang.reflect.Modifier.isStatic(m.getModifiers())) {
Class<?>[] p = m.getParameterTypes();
if (p.length != 1 || p[0] != Object.class)
throw new IllegalStateException("convertFromDef must be (Object) -> " + returnType);
}
}
} Try / catch
try {
new ScriptClassInfo(lookup, MyScript.class);
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("convertFromDef must take")) {
fail("Fix convertFromDef signature: must be static <R> convertFromDef(Object)");
}
throw e;
} Prevention
- Only add convertFromDef when you genuinely need def-to-return conversion.
- Keep its parameter strictly Object; do the narrowing inside the body.
- Unit-test the context interface before registering it.
When it happens
Trigger: Adding a static convertFromDef method to a custom script-context interface whose parameter is a narrower type than Object (e.g. convertFromDef(Double) or convertFromDef(Number)).
Common situations: Copy-pasting a convertFrom<ConcreteType> pattern and renaming it to convertFromDef without widening the parameter to Object; custom context for a plugin that wants def support.
Related errors
- Painless can only implement interfaces that have a single me
- no execute method found
- [{}#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/439f907f66641a9b.
Report an issue: GitHub.