{"record":{"id":"439f907f66641a9b","repo":"elastic/elasticsearch","slug":"convertfromdef-must-take-a-single-object-as-an-arg","errorCode":null,"errorMessage":"convertFromDef must take a single Object as an argument, not [{}]","messagePattern":"convertFromDef must take a single Object as an argument, not \\[(.+?)\\]","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java","lineNumber":111,"sourceCode":"                    );\n\n                }\n        }\n\n        if (executeMethod == null) {\n            throw new IllegalStateException(\"no execute method found\");\n        }\n        ArrayList<FunctionTable.LocalFunction> converters = new ArrayList<>();\n        FunctionTable.LocalFunction defConverter = null;\n        for (java.lang.reflect.Method m : baseClass.getMethods()) {\n            if (m.getName().startsWith(\"convertFrom\")\n                && m.getParameterTypes().length == 1\n                && m.getReturnType() == returnType\n                && Modifier.isStatic(m.getModifiers())) {\n\n                if (m.getName().equals(\"convertFromDef\")) {\n                    if (m.getParameterTypes()[0] != Object.class) {\n                        throw new IllegalStateException(\n                            \"convertFromDef must take a single Object as an argument, \" + \"not [\" + m.getParameterTypes()[0] + \"]\"\n                        );\n                    }\n                    defConverter = new FunctionTable.LocalFunction(\n                        m.getName(),\n                        m.getReturnType(),\n                        List.of(m.getParameterTypes()),\n                        true,\n                        true\n                    );\n                } else {\n                    converters.add(\n                        new FunctionTable.LocalFunction(m.getName(), m.getReturnType(), List.of(m.getParameterTypes()), true, true)\n                    );\n                }\n            }\n        }\n        this.defConverter = defConverter;","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java#L93-L129","documentation":"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.","triggerScenarios":"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)).","commonSituations":"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.","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."],"exampleFix":"// before\npublic interface MyScript {\n    double execute();\n    static double convertFromDef(Double v) { return v; } // -> 1343\n}\n// after\npublic interface MyScript {\n    double execute();\n    static double convertFromDef(Object v) { return ((Number) v).doubleValue(); }\n}","handlingStrategy":"validation","validationCode":"void assertConvertFromDefSignature(Class<?> iface, Class<?> returnType) {\n    for (java.lang.reflect.Method m : iface.getMethods()) {\n        if (m.getName().equals(\"convertFromDef\") && java.lang.reflect.Modifier.isStatic(m.getModifiers())) {\n            Class<?>[] p = m.getParameterTypes();\n            if (p.length != 1 || p[0] != Object.class)\n                throw new IllegalStateException(\"convertFromDef must be (Object) -> \" + returnType);\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    new ScriptClassInfo(lookup, MyScript.class);\n} catch (IllegalStateException e) {\n    if (e.getMessage().startsWith(\"convertFromDef must take\")) {\n        fail(\"Fix convertFromDef signature: must be static <R> convertFromDef(Object)\");\n    }\n    throw e;\n}","preventionTips":["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."],"tags":["painless","scripting","script-context","reflection","elasticsearch"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}