{"record":{"id":"62de9e34afa49f47","repo":"elastic/elasticsearch","slug":"unknown-variable","errorCode":null,"errorMessage":"Unknown variable [{}]","messagePattern":"Unknown variable \\[(.+?)\\]","errorType":"validation","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java","lineNumber":402,"sourceCode":"    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) {\n                variablename = parts[2].text;\n            } else {\n                throw new IllegalArgumentException(\n                    \"Only member variables or member methods may be accessed on a field when not accessing the field directly\"\n                );\n            }","sourceCodeStart":384,"sourceCodeEnd":420,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java#L384-L420","documentation":"Thrown in getDocValueSource() when the first segment of a parsed variable is not the literal text 'doc'. The expression engine expects variables to be either 'doc' (for field access), '_score', '_value', or user-supplied params. If the variable starts with something else and isn't in params, parsing reaches getDocValueSource and fails here.","triggerScenarios":"An expression references a bare variable name that is neither a doc field (doc['...']), a special variable (_score, _value), nor a param. Example: \"myvar * 2\" where 'myvar' is not passed in params.","commonSituations":"Forgetting to prefix field access with doc['...']; using a variable name that was intended as a param but not included in the params map; typo in a special variable name.","solutions":["Prefix field references with doc['fieldname'] — expressions require this syntax for field access.","If the variable is meant to be a runtime parameter, add it to the script's params map with a numeric value.","Use _score for the document's relevance score and _value for aggregation bucket values.","Check for typos in variable names against the params and field names."],"exampleFix":"// before: bare variable not in params\n\"source\": \"myvar * 2\"\n// after: either make it a param or use doc['field']\n\"source\": \"myvar * 2\", \"params\": {\"myvar\": 10.0}\n// or\n\"source\": \"doc['price'].value * 2\"","handlingStrategy":"validation","validationCode":"// Validate expression variables before execution\n// Every variable in the expression must be one of:\n//   - doc['fieldname']  (field access)\n//   - _score            (relevance score)\n//   - _value            (aggregation bucket value)\n//   - a key in params   (numeric param)\n// Check: if a variable doesn't start with 'doc', '_score', or '_value', it must be in params","typeGuard":null,"tryCatchPattern":"try {\n    engine.compile(scriptName, scriptSource, context, params);\n} catch (ScriptException e) {\n    if (e.getCause() instanceof ParseException && e.getCause().getMessage().contains(\"Unknown variable\")) {\n        String varName = extractVariableName(e.getCause().getMessage());\n        logger.error(\"Variable '{}' is not doc[], _score, _value, or a param\", varName);\n        // Add the variable to params or prefix with doc['']\n    }\n    throw e;\n}","preventionTips":["Always use doc['fieldname'] syntax for field access — never bare variable names.","Pass all runtime variables through the params map with numeric values.","Use _score only in score context and _value only in aggregation context.","Review expression source for any identifier that isn't a known field, param, or special variable."],"tags":["expression","script","variable","binding","field-access"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}