{"record":{"id":"95ad66a5dcce00b2","repo":"elastic/elasticsearch","slug":"expression-engine-does-not-know-how-to-handle-scri","errorCode":null,"errorMessage":"expression engine does not know how to handle script context [{}]","messagePattern":"expression engine does not know how to handle script context \\[(.+?)\\]","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java","lineNumber":164,"sourceCode":"        }\n    );\n\n    @Override\n    public String getType() {\n        return NAME;\n    }\n\n    @Override\n    public <T> T compile(String scriptName, String scriptSource, ScriptContext<T> context, Map<String, String> params) {\n        Expression expr;\n        try {\n            // NOTE: validation is delayed to allow runtime vars, and we don't have access to per index stuff here\n            expr = JavascriptCompiler.compile(scriptSource, JavascriptCompiler.DEFAULT_FUNCTIONS);\n        } catch (ParseException e) {\n            throw convertToScriptException(\"compile error\", scriptSource, scriptSource, e);\n        }\n        if (contexts.containsKey(context) == false) {\n            throw new IllegalArgumentException(\"expression engine does not know how to handle script context [\" + context.name + \"]\");\n        }\n        return context.factoryClazz.cast(contexts.get(context).apply(expr));\n    }\n\n    @Override\n    public Set<ScriptContext<?>> getSupportedContexts() {\n        return contexts.keySet();\n    }\n\n    private static BucketAggregationScript.Factory newBucketAggregationScriptFactory(Expression expr) {\n        return parameters -> {\n            ReplaceableConstDoubleValues[] functionValuesArray = new ReplaceableConstDoubleValues[expr.variables.length];\n            Map<String, ReplaceableConstDoubleValues> functionValuesMap = new HashMap<>();\n            for (int i = 0; i < expr.variables.length; ++i) {\n                functionValuesArray[i] = new ReplaceableConstDoubleValues();\n                functionValuesMap.put(expr.variables[i], functionValuesArray[i]);\n            }\n            return new BucketAggregationScript(parameters) {","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java#L146-L182","documentation":"Thrown in ExpressionScriptEngine.compile() when the requested ScriptContext is not in the supported contexts map. The expression engine only supports a fixed set of contexts: BucketAggregationScript, BucketAggregationSelectorScript, FilterScript, ScoreScript, TermsSetQueryScript, AggregationScript, NumberSortScript, FieldScript, and DoubleValuesScript. Any other context (e.g., ingest processor, update script, bulk ingest) is rejected at compile time.","triggerScenarios":"Submitting an expression script in a context the engine does not support — for example, using \"lang\":\"expression\" in an ingest pipeline processor, an update by query script, or any context whose ScriptContext is not registered in the contexts map at line 56-147.","commonSituations":"Migrating from Painless to expression for performance without realizing expression only supports read-time numeric contexts; trying to use expression in an ingest pipeline or update script.","solutions":["Switch to Painless (\"lang\":\"painless\") for unsupported contexts like ingest, update, or watcher scripts.","Verify the context is supported by checking ExpressionScriptEngine.getSupportedContexts().","Relocate the expression logic to a supported context: e.g., move computation from an ingest processor to a runtime field or script_score query.","Review the Elasticsearch expression documentation to confirm which APIs accept expression scripts."],"exampleFix":"// before: expression in ingest pipeline (unsupported)\nPUT _ingest/pipeline/my-pipeline\n{\n  \"processors\": [{\n    \"script\": { \"lang\": \"expression\", \"source\": \"doc['price'].value * 1.2\" }\n  }]\n}\n// after: use painless for ingest\nPUT _ingest/pipeline/my-pipeline\n{\n  \"processors\": [{\n    \"script\": { \"lang\": \"painless\", \"source\": \"ctx.price *= 1.2\" }\n  }]\n}","handlingStrategy":"validation","validationCode":"// Before compiling an expression script, verify the context is supported\nSet<ScriptContext<?>> supported = ExpressionScriptEngine.getSupportedContexts();\n// Or via REST: expression scripts only work in these contexts:\n//   function_score / script_score, runtime fields, sort, \n//   bucket_script / bucket_selector aggregations, terms_set query\n// Do NOT use in: ingest pipelines, update scripts, watcher actions","typeGuard":null,"tryCatchPattern":"// In plugin code, check supported contexts before compiling:\nif (engine.getSupportedContexts().contains(targetContext) == false) {\n    throw new IllegalArgumentException(\n        \"Expression engine does not support context \" + targetContext + \". Use Painless instead.\"\n    );\n}\nengine.compile(scriptName, scriptSource, targetContext, params);","preventionTips":["Check the Elasticsearch expression script documentation for the list of supported contexts before choosing \"lang\":\"expression\".","Use Painless for ingest, update, watcher, and any non-numeric/non-read context.","Expression scripts are optimized for read-only numeric computations — do not attempt to use them for data transformation.","If unsure, test in a non-production environment first."],"tags":["expression","script","context","compile-time","unsupported"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}