This error occurs when Elasticsearch cannot compile a Painless script due to syntax errors, invalid tokens, or other compilation issues in your script code.
The "ScriptException: compile error" indicates that Elasticsearch's Painless scripting engine encountered a problem while attempting to compile your script before execution. Painless is Elasticsearch's built-in scripting language used in queries, aggregations, updates, and ingest pipelines. When you submit a script to Elasticsearch, it first compiles it into bytecode before running it. If the script contains syntax errors, invalid operators, type mismatches, or other compilation issues, Elasticsearch rejects the request with a 400 (Bad Request) status and returns this ScriptException. The error response typically includes a "script_stack" field that shows where the error occurred, marked with "^---- HERE" to pinpoint the exact location of the problem in your script code.
Examine the error response to find the exact location of the compile error:
{
"error": {
"type": "script_exception",
"reason": "compile error",
"script_stack": [
"... if (ctx.field == 'value') {",
" ^---- HERE"
],
"caused_by": {
"type": "illegal_argument_exception",
"reason": "invalid sequence of tokens near ['value']."
}
}
}The "^---- HERE" marker shows exactly where the compilation failed.
Verify your script follows Painless syntax rules:
Missing semicolons:
// Wrong
def x = 1
def y = 2
// Correct
def x = 1;
def y = 2;Missing braces:
// Wrong
if (ctx.status == 'active')
ctx.count++
// Correct
if (ctx.status == 'active') {
ctx.count++;
}String comparison:
// Wrong (single equals in condition)
if (ctx.field = 'value') { }
// Correct (double equals)
if (ctx.field == 'value') { }When working with document context, use Debug.explain() to see what's available:
POST /my-index/_explain/1
{
"query": {
"script_score": {
"query": { "match_all": {} },
"script": {
"source": "Debug.explain(doc)"
}
}
}
}This shows the structure and types of fields you can access in your script.
Build your script gradually to isolate the problem:
POST /_scripts/painless/_execute
{
"script": {
"source": "return 1 + 1;"
}
}Add complexity step by step:
POST /_scripts/painless/_execute
{
"script": {
"source": """
def x = params.value;
if (x > 10) {
return x * 2;
}
return x;
""",
"params": {
"value": 15
}
}
}Painless has specific syntax requirements that differ from other languages:
Field access:
// Use doc['field'].value for doc values
doc['price'].value * 1.1
// Use params._source for source fields
params._source.nested.fieldSafe navigation:
// Handle missing fields
doc.containsKey('field') ? doc['field'].value : 0Ternary operators:
// Correct ternary syntax
def result = condition ? value1 : value2;Refer to the official Painless scripting guide for complete syntax rules.
Avoid using reserved Painless keywords as variable names:
// Wrong - 'in' is a reserved keyword
def in = 5;
// Correct - use different name
def input = 5;Common reserved words: if, else, for, while, return, def, true, false, null, in, instanceof.
Compilation Caching:
Elasticsearch caches compiled scripts to improve performance. The default limit is 100 cached scripts with a maximum size of 1000. Scripts are compiled on first use and evicted using LRU (Least Recently Used) policy. To see cache statistics:
GET /_nodes/stats/scriptDynamic Script Compilation Limits:
By default, Elasticsearch allows 150 script compilations per 5 minutes (75/5min for Painless specifically) to prevent circuit breaker exceptions. If you frequently compile unique scripts, consider using stored scripts or parameterized scripts instead:
PUT _scripts/my-script
{
"script": {
"lang": "painless",
"source": "doc['field'].value * params.multiplier"
}
}Then reference it by ID:
GET /my-index/_search
{
"query": {
"script_score": {
"query": { "match_all": {} },
"script": {
"id": "my-script",
"params": {
"multiplier": 2
}
}
}
}
}Type Strictness:
Painless enforces strong typing. All variables must have compatible types for operations. Use explicit casting when needed:
// Cast to specific type
int count = (int) doc['count'].value;
double price = (double) doc['price'].value;Debugging Strategy:
When facing complex compilation errors, extract the script to a text editor with Java syntax highlighting. Painless syntax closely resembles Java, so many IDEs can help identify syntax issues before you deploy to Elasticsearch.
QueryShardException: No mapping found for [field] in order to sort on
How to fix "QueryShardException: No mapping found for field in order to sort on" in Elasticsearch
IndexNotFoundException: no such index [index_name]
How to fix "IndexNotFoundException: no such index [index_name]" in Elasticsearch
DocumentMissingException: [index][type][id]: document missing
DocumentMissingException: Document missing
ParsingException: Unknown key for a START_OBJECT in [query]
How to fix "ParsingException: Unknown key for a START_OBJECT in [query]" in Elasticsearch
AggregationExecutionException: Aggregation [agg_name] does not support sampling
How to fix "AggregationExecutionException: Aggregation [agg_name] does not support sampling" in Elasticsearch