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

  1. Change the signature of convertFromDef to 'static <ReturnType> convertFromDef(Object value)'.
  2. If you did not intend def conversion, remove the convertFromDef method entirely (other convertFrom* methods are allowed).
  3. 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

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


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