{"record":{"id":"34fcfd5abafd9652","repo":"elastic/elasticsearch","slug":"compile-error","errorCode":null,"errorMessage":"compile error","messagePattern":"compile error","errorType":"exception","errorClass":"ScriptException","httpStatus":null,"severity":"error","filePath":"modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java","lineNumber":396,"sourceCode":"        return new ExpressionScoreScript(expr, bindings, needsScores);\n    }\n\n    /**\n     * converts a ParseException at compile-time or link-time to a ScriptException\n     */\n    private static ScriptException convertToScriptException(String message, String source, String portion, Throwable cause) {\n        List<String> stack = new ArrayList<>();\n        stack.add(portion);\n        StringBuilder pointer = new StringBuilder();\n        if (cause instanceof ParseException) {\n            int offset = ((ParseException) cause).getErrorOffset();\n            for (int i = 0; i < offset; i++) {\n                pointer.append(' ');\n            }\n        }\n        pointer.append(\"^---- HERE\");\n        stack.add(pointer.toString());\n        throw new ScriptException(message, cause, stack, source, NAME);\n    }\n\n    private static DoubleValuesSource getDocValueSource(String variable, SearchLookup lookup) throws ParseException {\n        VariableContext[] parts = VariableContext.parse(variable);\n        if (parts[0].text.equals(\"doc\") == false) {\n            throw new ParseException(\"Unknown variable [\" + parts[0].text + \"]\", 0);\n        }\n        if (parts.length < 2 || parts[1].type != VariableContext.Type.STR_INDEX) {\n            throw new ParseException(\"Variable 'doc' must be used with a specific field like: doc['myfield']\", 3);\n        }\n\n        // .value is the default for doc['field'], its optional.\n        String variablename = \"value\";\n        String methodname = null;\n        if (parts.length == 3) {\n            if (parts[2].type == VariableContext.Type.METHOD) {\n                methodname = parts[2].text;\n            } else if (parts[2].type == VariableContext.Type.MEMBER) {","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java#L378-L414","documentation":"Thrown by convertToScriptException with message \"compile error\" when JavascriptCompiler.compile() raises a ParseException during expression parsing. The resulting ScriptException includes the source text, a stack with a pointer to the error offset, and the original ParseException as cause. This is a syntax-level failure in the expression source string.","triggerScenarios":"Submitting an expression script with invalid JavaScript-like syntax — e.g., unbalanced parentheses, unknown operators, invalid variable names, or malformed function calls. Example: \"doc['price'.value\" (missing bracket) or \"doc['price'] ++ value\" (invalid operator).","commonSituations":"Typos in expression source; copy-paste errors; dynamically generated expressions with unescaped user input; attempting to use syntax features not supported by Lucene's expression compiler (no loops, no conditionals, no string operations).","solutions":["Check the ScriptException stack trace — it includes a '^---- HERE' pointer showing the exact character offset of the syntax error.","Validate the expression syntax: expressions support only arithmetic (+, -, *, /, %, bitwise &, |, ^, shift), comparison, ternary, and function calls from DEFAULT_FUNCTIONS.","Balance all parentheses and brackets; ensure string literals in doc['field'] use single quotes."],"exampleFix":"// before: missing closing bracket\n\"source\": \"doc['price'.value * 1.2\"\n// after: close the bracket\n\"source\": \"doc['price'].value * 1.2\"","handlingStrategy":"validation","validationCode":"// Validate expression syntax before deployment by compiling in a test\n// Expression supports: arithmetic, bitwise, comparison, ternary, and DEFAULT_FUNCTIONS\n// Does NOT support: loops, if/else blocks, string ops, variable assignment\n// Quick test: run a trivial query with the expression\nGET my-index/_search\n{ \"query\": { \"function_score\": { \"script_score\": { \"script\": { \"lang\": \"expression\", \"source\": \"<YOUR_EXPRESSION>\" } } } } }","typeGuard":null,"tryCatchPattern":"// When compiling expressions programmatically:\ntry {\n    engine.compile(scriptName, scriptSource, context, params);\n} catch (ScriptException e) {\n    if (\"compile error\".equals(e.getScriptStack().get(0)) || e.getMessage().contains(\"compile error\")) {\n        // Syntax error — check the ^--- HERE pointer in the stack\n        logger.error(\"Expression syntax error at offset: {}\", e.getScriptStack());\n    }\n    throw e;\n}","preventionTips":["Always test expression syntax in a non-production index before deployment.","Use the ^---- HERE pointer in the ScriptException stack to locate syntax errors quickly.","Remember expression syntax is a restricted subset — no loops, conditionals (beyond ternary), or string operations.","Validate dynamically generated expressions with a linting step before submitting them."],"tags":["expression","script","compile","syntax-error","parse"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}