{"record":{"id":"c6120421d71bbf1d","repo":"spring-projects/spring-ai","slug":"the-template-string-is-not-valid","errorCode":null,"errorMessage":"The template string is not valid.","messagePattern":"The template string is not valid\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-template-st/src/main/java/org/springframework/ai/template/st/StTemplateRenderer.java","lineNumber":123,"sourceCode":"\n\t\tST st = createST(template);\n\t\tfor (Map.Entry<String, ? extends @Nullable Object> entry : variables.entrySet()) {\n\t\t\tst.add(entry.getKey(), entry.getValue());\n\t\t}\n\t\tif (this.validationMode != ValidationMode.NONE) {\n\t\t\tvalidate(st, variables);\n\t\t}\n\t\treturn st.render();\n\t}\n\n\tprivate ST createST(String template) {\n\t\ttry {\n\t\t\tSTGroup group = new STGroup(this.startDelimiterToken, this.endDelimiterToken);\n\t\t\tgroup.setListener(new CommonsLoggingStErrorListener(logger));\n\t\t\treturn new ST(group, template);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalArgumentException(\"The template string is not valid.\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Validates that all required template variables are provided in the model. Returns\n\t * the set of missing variables for further handling or logging.\n\t * @param st the StringTemplate instance\n\t * @param templateVariables the provided variables\n\t * @return set of missing variable names, or empty set if none are missing\n\t */\n\tprivate Set<String> validate(ST st, Map<String, ? extends @Nullable Object> templateVariables) {\n\t\tSet<String> templateTokens = getInputVariables(st);\n\t\tSet<String> modelKeys = templateVariables.keySet();\n\t\tSet<String> missingVariables = new HashSet<>(templateTokens);\n\t\tmissingVariables.removeAll(modelKeys);\n\n\t\tif (!missingVariables.isEmpty()) {\n\t\t\tif (this.validationMode == ValidationMode.WARN) {","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-template-st/src/main/java/org/springframework/ai/template/st/StTemplateRenderer.java#L105-L141","documentation":"StTemplateRenderer.createST wraps StringTemplate group/template construction; any exception while creating the ST from the template string is rethrown as IllegalArgumentException('The template string is not valid.', ex). The underlying cause (from the CommonsLoggingStErrorListener/ST internals) explains what syntax was wrong.","triggerScenarios":"Calling render with a template containing StringTemplate syntax errors — unbalanced or unescaped delimiters, stray '{' or '}' (matching the configured start/end delimiter tokens), invalid attribute expressions — via PromptTemplate using StTemplateRenderer.","commonSituations":"Prompts that include literal JSON or code with curly braces not escaped; mismatched custom delimiter tokens; typos in attribute expressions like {question_answer_contex}; migrating from another template engine whose syntax differs.","solutions":["Inspect the wrapped cause 'ex' — it names the exact ST syntax error and position","Escape or reformat literal braces in the prompt (e.g. JSON examples) so they don't parse as expressions","Align the start/end delimiter tokens with your template syntax (e.g. use '<' '>' if braces collide with JSON)","Validate attribute names in the template match the model map keys exactly"],"exampleFix":"// before\nString template = \"Respond with JSON: {\\\"answer\\\": {answer}}\"; // braces conflict\n// after (custom delimiters)\nStTemplateRenderer renderer = StTemplateRenderer.builder()\n    .startDelimiterToken('<').endDelimiterToken('>').build();\nString template = \"Respond with JSON: {\\\"answer\\\": <answer>}\";","handlingStrategy":"validation","validationCode":"try {\n    new STGroup(renderer instanceof Object /* config */ ? \"{\" : \"<\", \"}\");\n} catch (Exception e) { /* delimiter config wrong */ }\n// assert no unbalanced braces outside known placeholders:\nlong open = template.chars().filter(c -> c == '{').count();\nlong close = template.chars().filter(c -> c == '}').count();\nif (open != close) throw new IllegalStateException(\"Unbalanced braces in template\");","typeGuard":null,"tryCatchPattern":"try { rendered = renderer.render(template, model); }\ncatch (IllegalArgumentException e) {\n    if (\"The template string is not valid.\".equals(e.getMessage())) { log.error(\"ST syntax error\", e.getCause()); }\n}","preventionTips":["Escape literal braces (JSON/code samples) in prompts or switch delimiters to < >","Render templates in unit tests before deploying prompts","Keep attribute names in sync with model map keys","Always log the cause — ST reports exact error positions"],"tags":["stringtemplate","template-rendering","syntax"],"backgroundTag":"invalid-regex-pattern","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}