{"record":{"id":"c2abc44fd508d6b5","repo":"elastic/elasticsearch","slug":"could-not-parse-inline-template","errorCode":null,"errorMessage":"Could not parse inline template","messagePattern":"Could not parse inline template","errorType":"validation","errorClass":"ParsingException","httpStatus":null,"severity":"error","filePath":"modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/SearchTemplateRequest.java","lineNumber":217,"sourceCode":"    private static final ObjectParser<SearchTemplateRequest, Void> PARSER;\n\n    static {\n        PARSER = new ObjectParser<>(\"search_template\");\n        PARSER.declareField((parser, request, s) -> request.setScriptParams(parser.map()), PARAMS_FIELD, ObjectParser.ValueType.OBJECT);\n        PARSER.declareString((request, s) -> {\n            request.setScriptType(ScriptType.STORED);\n            request.setScript(s);\n        }, ID_FIELD);\n        PARSER.declareBoolean(SearchTemplateRequest::setExplain, EXPLAIN_FIELD);\n        PARSER.declareBoolean(SearchTemplateRequest::setProfile, PROFILE_FIELD);\n        PARSER.declareField((parser, request, value) -> {\n            request.setScriptType(ScriptType.INLINE);\n            if (parser.currentToken() == XContentParser.Token.START_OBJECT) {\n                // convert the template to json which is the only supported XContentType (see CustomMustacheFactory#createEncoder)\n                try (XContentBuilder builder = XContentFactory.jsonBuilder()) {\n                    request.setScript(Strings.toString(builder.copyCurrentStructure(parser)));\n                } catch (IOException e) {\n                    throw new ParsingException(parser.getTokenLocation(), \"Could not parse inline template\", e);\n                }\n            } else {\n                request.setScript(parser.text());\n            }\n        }, SOURCE_FIELD, ObjectParser.ValueType.OBJECT_OR_STRING);\n        PARSER.declareString(SearchTemplateRequest::setProjectRouting, PROJECT_ROUTING_FIELD);\n    }\n\n    public static SearchTemplateRequest fromXContent(XContentParser parser) throws IOException {\n        return PARSER.parse(parser, new SearchTemplateRequest(), null);\n    }\n\n    @Override\n    public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {\n        builder.startObject();\n\n        if (scriptType == ScriptType.STORED) {\n            builder.field(ID_FIELD.getPreferredName(), script);","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/SearchTemplateRequest.java#L199-L235","documentation":"Raised while parsing the inline template ('source' field) when it is provided as a JSON object (START_OBJECT) and copying that structure into a JSON XContentBuilder throws an IOException. The template engine only supports JSON-encoded inline templates, so any I/O or structural failure during the copy is wrapped as a ParsingException located at the parser's current token.","triggerScenarios":"POSTing _search/template with \"source\" as an object whose content triggers an IOException during XContent copy — e.g. malformed nested structure, an invalid token sequence, or an encoding issue in the stream. The field is declared OBJECT_OR_STRING, so an object form is accepted but must be fully copyable.","commonSituations":"Hand-constructing a template body with an unterminated object or a stray token. Sending a template originally written in Smile/YAML/CBOR but labeled as JSON. Upgrading a client that changed serialization and now emits a partially-valid object. Network/proxy truncating the request mid-object.","solutions":["Validate the 'source' object is well-formed JSON before sending (run it through a JSON linter).","If the template is a simple string, pass it as a VALUE_STRING instead of a START_OBJECT to bypass the copy path.","Ensure the request Content-Type matches the actual body encoding (application/json for a JSON object).","Reproduce locally with a minimal template and bisect to find the offending nested element."],"exampleFix":"// before (malformed object)\n{\"source\":{\"query\":{\"match\":{ \"title\": \"star\" }}, \"params\":{}}\n// after (valid, and as string form)\n{\"source\":\"{\\\"query\\\":{\\\"match_all\\\":{}}}\",\"params\":{}}","handlingStrategy":"validation","validationCode":"// Validate inline template object is well-formed JSON before sending\nfunction validateInlineTemplate(body) {\n  if (body.source && typeof body.source === 'object') {\n    // Re-serialize to confirm it round-trips cleanly\n    JSON.stringify(body.source);\n  } else if (body.source && typeof body.source === 'string') {\n    JSON.parse(body.source); // will throw if malformed string-as-json\n  }\n  return true;\n}","typeGuard":null,"tryCatchPattern":"// catch (ElasticsearchStatusException e) where message starts with 'Could not parse inline template' -> surface the body's 'source' for the user to fix","preventionTips":["Prefer the string form of 'source' when the template is already JSON text.","Set Content-Type: application/json explicitly on the request.","Lint the template object in CI for stored templates."],"tags":["request-validation","search-template","mustache","xcontent","parsing"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}