{"record":{"id":"c9e789928047293c","repo":"elastic/elasticsearch","slug":"painless-needs-a-constant-string-parameters-on","errorCode":null,"errorMessage":"Painless needs a constant [String[] PARAMETERS] on all interfaces it implements with the names of the method arguments but [{}] doesn't have one.","messagePattern":"Painless needs a constant \\[String\\[\\] PARAMETERS\\] on all interfaces it implements with the names of the method arguments but \\[(.+?)\\] doesn't have one\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java","lineNumber":280,"sourceCode":"        Class<?> componentType = type;\n\n        while (componentType.isArray()) {\n            componentType = componentType.getComponentType();\n        }\n\n        if (componentType != def.class && painlessLookup.lookupPainlessClass(componentType) == null) {\n            throw new IllegalArgumentException(unknownErrorMessageSource.apply(componentType));\n        }\n\n        return type;\n    }\n\n    private static String[] readArgumentNamesConstant(Class<?> iface) {\n        Field argumentNamesField;\n        try {\n            argumentNamesField = iface.getField(\"PARAMETERS\");\n        } catch (NoSuchFieldException e) {\n            throw new IllegalArgumentException(\n                \"Painless needs a constant [String[] PARAMETERS] on all interfaces it implements with the \"\n                    + \"names of the method arguments but [\"\n                    + iface.getName()\n                    + \"] doesn't have one.\",\n                e\n            );\n        }\n        if (false == argumentNamesField.getType().equals(String[].class)) {\n            throw new IllegalArgumentException(\n                \"Painless needs a constant [String[] PARAMETERS] on all interfaces it implements with the \"\n                    + \"names of the method arguments but [\"\n                    + iface.getName()\n                    + \"] doesn't have one.\"\n            );\n        }\n        try {\n            return (String[]) argumentNamesField.get(null);\n        } catch (IllegalArgumentException | IllegalAccessException e) {","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java#L262-L298","documentation":"readArgumentNamesConstant reflectively looks up a public field named PARAMETERS on the context interface. If no such field exists (NoSuchFieldException), this IllegalArgumentException is thrown with the interface name and the original exception chained. Every Painless-implementable interface must declare 'public static final String[] PARAMETERS'.","triggerScenarios":"Registering a custom script-context interface that omits the PARAMETERS field entirely, names it differently (e.g. ARG_NAMES), or declares it non-public so getField cannot see it.","commonSituations":"Hand-writing a context interface and forgetting the PARAMETERS constant; copy-pasting from a non-Painless interface; field declared as private or with a typo in the name.","solutions":["Add 'String[] PARAMETERS = {\"name1\", \"name2\", ...};' as a public static final field on the interface.","Ensure the field name is exactly PARAMETERS (case-sensitive) and is public.","Match the array length to execute's parameter count (see error 1344)."],"exampleFix":"// before\npublic interface MyScript {\n    double execute(Map<String,Object> params); // no PARAMETERS -> 1345\n}\n// after\npublic interface MyScript {\n    String[] PARAMETERS = {\"params\"};\n    double execute(Map<String,Object> params);\n}","handlingStrategy":"validation","validationCode":"void assertHasParametersField(Class<?> iface) {\n    try { iface.getField(\"PARAMETERS\"); }\n    catch (NoSuchFieldException e) {\n        throw new IllegalStateException(\"Add public static final String[] PARAMETERS to \" + iface.getName());\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    new ScriptClassInfo(lookup, MyScript.class);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"doesn't have one\") && e.getCause() instanceof NoSuchFieldException) {\n        fail(\"Declare PARAMETERS field on the interface\");\n    }\n    throw e;\n}","preventionTips":["Always declare 'public static final String[] PARAMETERS' on any Painless context interface.","Use the existing built-in contexts (FilterScript, ScoreScript) as templates.","Add a CI check that scans context interfaces for the PARAMETERS field."],"tags":["painless","scripting","script-context","reflection","elasticsearch"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}