elastic/elasticsearch · error · ScriptException
link error
Error message
link error
What it means
Thrown by convertToScriptException with message "link error" during the variable binding phase in newSortScript, newScoreScript, newAggregationScript, newFieldScript, newTermsSetQueryScript. After compilation succeeds, each variable in the expression is bound to a DoubleValuesSource; if binding fails (field doesn't exist, wrong type, param not numeric), the exception is caught and re-thrown as a ScriptException with "link error" and the offending variable name as the stack portion.
Source
Thrown at modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java:396
return new ExpressionScoreScript(expr, bindings, needsScores);
}
/**
* converts a ParseException at compile-time or link-time to a ScriptException
*/
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) {View on GitHub (pinned to db6a809a66)
Solutions
- Read the ScriptException stack — the portion line shows which variable failed to bind.
- Verify the field exists in the index mapping: GET <index>/_mapping.
- Confirm the field type is numeric (integer, long, float, double, scaled_float), date, or geo_point — text and keyword are not supported.
- If the variable is a param, ensure its value is numeric (see error 1237).
Example fix
// before: field 'price' does not exist or is type text "source": "doc['price'].value" // after: verify mapping and use correct field GET my-index/_mapping // if field is missing, add it or use the correct name "source": "doc['amount'].value"
Defensive patterns
Strategy: validation
Validate before calling
// Before using an expression, validate that all doc['field'] references exist and are the right type GET my-index/_mapping // For each doc['fieldname'] in the expression, confirm: // 1. fieldname exists in the mapping // 2. field type is numeric, date, or geo_point // 3. doc_values is not disabled
Try / catch
try {
engine.compile(scriptName, scriptSource, context, params);
} catch (ScriptException e) {
if ("link error".equals(e.getScriptStack().get(0)) || e.getMessage().contains("link error")) {
// The portion line in the stack names the variable that failed to bind
logger.error("Expression link error for variable: {}", e.getScriptStack());
// Check mapping, field type, and param types
}
throw e;
} Prevention
- Always validate field names against the index mapping before deploying expressions.
- Confirm field types are numeric, date, or geo_point — text/keyword/boolean are not supported.
- When a mapping changes, audit all expression scripts that reference the changed fields.
- Use the link error's variable name in the ScriptException stack to identify which field failed.
When it happens
Trigger: Expression compiles successfully but references a doc['fieldname'] where 'fieldname' does not exist in the mapping, is not numeric/date/geo, or a param value is non-numeric. Example: expression "doc['nonexistent'].value" passes parsing but fails at binding time.
Common situations: Field renamed or removed from mapping without updating scripts; typo in field name inside the expression; field exists but is of type text/keyword (not supported by expressions); param value type mismatch.
Related errors
- Field [{}] does not exist in mappings
- compile error
- Unknown variable [{}]
- Field [{}] must be numeric, date, or geopoint
- Can't advance to doc using {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/57ebd7ca1b552b4b.
Report an issue: GitHub.