elastic/elasticsearch · error · ParseException

Unknown variable [{}]

Error message

Unknown variable [{}]

What it means

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.

Source

Thrown at modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java:402

    private static ScriptException convertToScriptException(String message, String source, String portion, Throwable cause) {
        List<String> stack = new ArrayList<>();
        stack.add(portion);
        StringBuilder pointer = new StringBuilder();
        if (cause instanceof ParseException) {
            int offset = ((ParseException) cause).getErrorOffset();
            for (int i = 0; i < offset; i++) {
                pointer.append(' ');
            }
        }
        pointer.append("^---- HERE");
        stack.add(pointer.toString());
        throw new ScriptException(message, cause, stack, source, NAME);
    }

    private static DoubleValuesSource getDocValueSource(String variable, SearchLookup lookup) throws ParseException {
        VariableContext[] parts = VariableContext.parse(variable);
        if (parts[0].text.equals("doc") == false) {
            throw new ParseException("Unknown variable [" + parts[0].text + "]", 0);
        }
        if (parts.length < 2 || parts[1].type != VariableContext.Type.STR_INDEX) {
            throw new ParseException("Variable 'doc' must be used with a specific field like: doc['myfield']", 3);
        }

        // .value is the default for doc['field'], its optional.
        String variablename = "value";
        String methodname = null;
        if (parts.length == 3) {
            if (parts[2].type == VariableContext.Type.METHOD) {
                methodname = parts[2].text;
            } else if (parts[2].type == VariableContext.Type.MEMBER) {
                variablename = parts[2].text;
            } else {
                throw new IllegalArgumentException(
                    "Only member variables or member methods may be accessed on a field when not accessing the field directly"
                );
            }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Prefix field references with doc['fieldname'] — expressions require this syntax for field access.
  2. If the variable is meant to be a runtime parameter, add it to the script's params map with a numeric value.
  3. Use _score for the document's relevance score and _value for aggregation bucket values.
  4. Check for typos in variable names against the params and field names.

Example fix

// before: bare variable not in params
"source": "myvar * 2"
// after: either make it a param or use doc['field']
"source": "myvar * 2", "params": {"myvar": 10.0}
// or
"source": "doc['price'].value * 2"
Defensive patterns

Strategy: validation

Validate before calling

// Validate expression variables before execution
// Every variable in the expression must be one of:
//   - doc['fieldname']  (field access)
//   - _score            (relevance score)
//   - _value            (aggregation bucket value)
//   - a key in params   (numeric param)
// Check: if a variable doesn't start with 'doc', '_score', or '_value', it must be in params

Try / catch

try {
    engine.compile(scriptName, scriptSource, context, params);
} catch (ScriptException e) {
    if (e.getCause() instanceof ParseException && e.getCause().getMessage().contains("Unknown variable")) {
        String varName = extractVariableName(e.getCause().getMessage());
        logger.error("Variable '{}' is not doc[], _score, _value, or a param", varName);
        // Add the variable to params or prefix with doc['']
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/62de9e34afa49f47. Report an issue: GitHub.