{"record":{"id":"c9cb89a3597c3646","repo":"elastic/elasticsearch","slug":"error-using-executable-expressions-scripts-can","errorCode":null,"errorMessage":"Error using {}. Executable expressions scripts can only process numbers.  The variable [{}] is not a number.","messagePattern":"Error using (.+?)\\. Executable expressions scripts can only process numbers\\.  The variable \\[(.+?)\\] is not a number\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java","lineNumber":197,"sourceCode":"                functionValuesArray[i] = new ReplaceableConstDoubleValues();\n                functionValuesMap.put(expr.variables[i], functionValuesArray[i]);\n            }\n            return new BucketAggregationScript(parameters) {\n                @Override\n                public Double execute() {\n                    getParams().forEach((name, value) -> {\n                        ReplaceableConstDoubleValues placeholder = functionValuesMap.get(name);\n                        if (placeholder == null) {\n                            throw new IllegalArgumentException(\n                                \"Error using \"\n                                    + expr\n                                    + \". \"\n                                    + \"The variable [\"\n                                    + name\n                                    + \"] does not exist in the executable expressions script.\"\n                            );\n                        } else if (value instanceof Number == false) {\n                            throw new IllegalArgumentException(\n                                \"Error using \"\n                                    + expr\n                                    + \". \"\n                                    + \"Executable expressions scripts can only process numbers.\"\n                                    + \"  The variable [\"\n                                    + name\n                                    + \"] is not a number.\"\n                            );\n                        } else {\n                            placeholder.setValue(((Number) value).doubleValue());\n                        }\n                    });\n                    try {\n                        return expr.evaluate(functionValuesArray);\n                    } catch (IOException e) {\n                        throw new UncheckedIOException(e);\n                    }\n                }","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java#L179-L215","documentation":"Thrown inside BucketAggregationScript.execute() when a parameter value is not an instance of Number. The expression engine can only process numeric values; it checks value instanceof Number and throws IllegalArgumentException if the check fails, naming the offending variable.","triggerScenarios":"Passing a non-numeric param (String, Boolean, List, Map) to a bucket aggregation expression script. For example, params: {\"factor\": \"1.5\"} where the value is a String instead of a number.","commonSituations":"JSON parsing produces String for values that should be numeric (e.g., quoted numbers in the params block); dynamic param construction using the wrong type; migrating from Painless where type coercion was automatic.","solutions":["Ensure all param values are JSON numbers (unquoted), not strings: use {\"factor\": 1.5} not {\"factor\": \"1.5\"}.","If generating params programmatically, cast or convert values to numeric types before passing them.","Validate the params map type before script execution — reject any value that is not an instance of Number.","If the value must be a string (e.g., a field name), use Painless instead of expression."],"exampleFix":"// before: factor is a string\n\"params\": {\"factor\": \"1.5\"}\n// after: factor is a number\n\"params\": {\"factor\": 1.5}","handlingStrategy":"type-guard","validationCode":"// Validate all param values are numeric before passing to the script\nMap<String, Object> params = new HashMap<>();\nfor (Map.Entry<String, Object> entry : rawParams.entrySet()) {\n    if (entry.getValue() instanceof Number == false) {\n        throw new IllegalArgumentException(\n            \"Param '\" + entry.getKey() + \"' must be numeric, got: \" + entry.getValue().getClass()\n        );\n    }\n    params.put(entry.getKey(), entry.getValue());\n}","typeGuard":"// Type guard for numeric params\nstatic boolean isNumericParam(Object value) {\n    return value instanceof Number;\n}\n\n// Usage:\nfor (Map.Entry<String, Object> e : params.entrySet()) {\n    if (!isNumericParam(e.getValue())) {\n        throw new IllegalArgumentException(\"Non-numeric param: \" + e.getKey());\n    }\n}","tryCatchPattern":"try {\n    Double result = bucketScript.execute();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"not a number\")) {\n        logger.error(\"Non-numeric param in bucket script: {}\", e.getMessage());\n        // Fix the param type and retry\n    }\n    throw e;\n}","preventionTips":["Always use JSON numeric literals (unquoted) for numeric params in REST API calls.","In application code, enforce Number types before building the params map.","Add a validation layer between external config and script params to catch type mismatches early.","Document which params must be numeric in your script configuration schema."],"tags":["expression","script","aggregation","params","type-error"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}