{"record":{"id":"ac982d96788ecd37","repo":"elastic/elasticsearch","slug":"mustache-function-must-contain-one-and-only-o","errorCode":null,"errorMessage":"Mustache function [{}] must contain one and only one identifier","messagePattern":"Mustache function \\[(.+?)\\] must contain one and only one identifier","errorType":"validation","errorClass":"MustacheException","httpStatus":null,"severity":"error","filePath":"modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/CustomMustacheFactory.java","lineNumber":193,"sourceCode":"\n        @Override\n        protected void tag(Writer writer, String tag) throws IOException {\n            writer.write(tc.startChars());\n            writer.write(tag);\n            writer.write(code);\n            writer.write(tc.endChars());\n        }\n\n        protected abstract Function<String, String> createFunction(Object resolved);\n\n        /**\n         * At compile time, this function extracts the name of the variable:\n         * {{#toJson}}variable_name{{/toJson}}\n         */\n        protected static String extractVariableName(String fn, Mustache mustache, TemplateContext tc) {\n            Code[] codes = mustache.getCodes();\n            if (codes == null || codes.length != 1) {\n                throw new MustacheException(\"Mustache function [\" + fn + \"] must contain one and only one identifier\");\n            }\n\n            try (StringWriter capture = new StringWriter()) {\n                // Variable name is in plain text and has type WriteCode\n                if (codes[0] instanceof WriteCode) {\n                    codes[0].execute(capture, List.of());\n                } else {\n                    codes[0].identity(capture);\n                }\n                return capture.toString();\n            } catch (IOException e) {\n                throw new MustacheException(\"Exception while parsing mustache function [\" + fn + \"] at line \" + tc.line(), e);\n            }\n        }\n    }\n\n    /**\n     * This function renders {@link Iterable} and {@link Map} as their JSON representation","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/CustomMustacheFactory.java#L175-L211","documentation":"Thrown by CustomCode.extractVariableName() at compile time when a custom mustache function (toJson, join, url) contains zero or more than one inner code element. The function parsing expects exactly one identifier inside the function block, e.g., {{#toJson}}variable_name{{/toJson}}. If codes is null or codes.length != 1, the function cannot determine which variable to resolve.","triggerScenarios":"Writing a custom function block with no content, empty content, or multiple variables inside. Example: {{#toJson}}{{var1}}{{var2}}{{/toJson}} (two variables) or {{#toJson}}{{/toJson}} (empty). The mustache compiler produces a Code array from the block content, and extractVariableName checks its length at compile time.","commonSituations":"Putting multiple variables inside a {{#toJson}}...{{/toJson}} block expecting them to be merged into one JSON object. Leaving the function block empty. Nesting sections or conditionals inside a function block. Using complex expressions instead of a bare variable name.","solutions":["Put exactly one variable name inside the function block: {{#toJson}}myvar{{/toJson}}","If you need multiple values as JSON, pass them as a single array or map parameter: {{#toJson}}multi_value_param{{/toJson}} where the param is an array","Ensure the block contains only the variable name with no extra whitespace-only or empty codes","Use {{#join}}myvar{{/join}} (single variable that resolves to an Iterable) for delimiter joining"],"exampleFix":"// before — two variables inside toJson:\n{{#toJson}}{{field1}}{{field2}}{{/toJson}}\n\n// after — single variable (pass combined data as one param):\n{{#toJson}}combined{{/toJson}}\n// where 'combined' is provided as a Map or List in params","handlingStrategy":"validation","validationCode":"// Validate that custom function blocks contain exactly one identifier\n// Parse template and check each {{#toJson}}, {{#join}}, {{#url}} block\n// has exactly one variable reference inside","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Put exactly one variable name inside {{#toJson}}...{{/toJson}} and similar blocks","Pass arrays/maps as a single param rather than multiple variables inside a function","Keep function blocks minimal: {{#toJson}}singleVar{{/toJson}}"],"tags":["elasticsearch","lang-mustache","tojson","join","compile","template"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}