{"record":{"id":"eb4d90881a6d9f47","repo":"elastic/elasticsearch","slug":"compile-error-eb4d90","errorCode":null,"errorMessage":"compile error","messagePattern":"compile error","errorType":"exception","errorClass":"ScriptException","httpStatus":null,"severity":"error","filePath":"modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java","lineNumber":497,"sourceCode":"                        snippet.append(\" ...\");\n                    }\n                    scriptStack.add(snippet.toString());\n                    StringBuilder pointer = new StringBuilder();\n                    if (startOffset > 0) {\n                        pointer.append(\"    \");\n                    }\n                    for (int i = startOffset; i < offset; i++) {\n                        pointer.append(' ');\n                    }\n                    pointer.append(\"^---- HERE\");\n                    scriptStack.add(pointer.toString());\n                    pos = new ScriptException.Position(originalOffset, startOffset, endOffset);\n                }\n                break;\n            }\n        }\n        Throwable cause = ErrorCauseWrapper.maybeWrap(t);\n        throw new ScriptException(\"compile error\", cause, scriptStack, scriptSource, PainlessScriptEngine.NAME, pos);\n    }\n\n    // very simple heuristic: +/- 25 chars. can be improved later.\n    private static int getPreviousStatement(int offset) {\n        return Math.max(0, offset - 25);\n    }\n\n    private static int getNextStatement(String scriptSource, int offset) {\n        return Math.min(scriptSource.length(), offset + 25);\n    }\n}\n","sourceCodeStart":479,"sourceCodeEnd":509,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java#L479-L509","documentation":"This is the catch-all wrapper thrown by convertToScriptException whenever ANY underlying error occurs while compiling a Painless script (syntax, type, reference, etc.). The original throwable is wrapped via ErrorCauseWrapper.maybeWrap and rethrown as a ScriptException whose message is the literal string 'compile error'. The real diagnostic is in the cause and in the scriptStack list, which contains a snippet of the failing script region plus a '^---- HERE' pointer line computed from the WriterConstants.CLASS_NAME stack frame.","triggerScenarios":"Compiling any Painless script that has a syntax error, references an undefined variable/function, performs a disallowed cast, or uses an un-whitelisted API. The trigger is compile() failing and control reaching the throw at line 497 of PainlessScriptEngine. Common entry points: _scripts/painless/_execute, inline scripts in _search, runtime fields, ingest pipelines, or any ScriptService.compile call.","commonSituations":"Typo in a Painless script field name; using a Java API that is not whitelisted for Painless; version upgrade that removed or renamed a previously allowed method; passing the wrong script context; dynamic/scripted_field with invalid syntax.","solutions":["Inspect the ScriptException.getScriptStack() and getCause() — the snippet and '^---- HERE' pointer pinpoint the failing offset in the script.","Fix the syntax/type/reference error in the script text indicated by the cause.","If the cause references an un-whitelisted method, replace it with an allowed Painless API or add an allowlist entry if you maintain a custom context.","Re-run with the corrected script; the 'compile error' wrapper disappears once the underlying compile succeeds."],"exampleFix":"// before (invalid: undeclared variable)\n{\"script\": {\"source\": \"doc['price'].value * faktor\"}}\n// after\n{\"script\": {\"source\": \"doc['price'].value * factor\"}}","handlingStrategy":"try-catch","validationCode":"// Validate script source before sending: a lightweight pre-check is not possible generically,\n// but you can catch the wrapped exception and surface the cause.\ntry {\n    scriptService.compile(script, context);\n} catch (ScriptException e) {\n    // real error is e.getCause() and e.getScriptStack()\n}","typeGuard":null,"tryCatchPattern":"try {\n    CompiledScript compiled = scriptService.compile(script, ScriptContext.Standard.SEARCH);\n} catch (ScriptException e) {\n    List<String> stack = e.getScriptStack(); // snippet + '^---- HERE' pointer\n    Throwable cause = e.getCause();          // underlying compile error\n    log.warn(\"Painless compile failed: {} | stack:{}\", cause, stack);\n    throw e;\n}","preventionTips":["Always read getScriptStack() and getCause() — the 'compile error' string itself carries no detail.","Develop scripts in Kibana's Dev Console or the _execute API first to get fast feedback before deploying.","Pin your ES version so whitelisted APIs do not silently change."],"tags":["painless","scripting","compile","elasticsearch"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}