{"record":{"id":"057a7447dcdaf2b2","repo":"alibaba/spring-ai-alibaba","slug":"the-template-string-is-not-valid","errorCode":null,"errorMessage":"The template string is not valid.","messagePattern":"The template string is not valid\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/renderer/SaaStTemplateRenderer.java","lineNumber":165,"sourceCode":"\t}\n\n\tprivate ST createST(String template) {\n\t\ttry {\n\t\t\tString processedTemplate = template;\n\t\t\t// If using string delimiters, convert them to single-char delimiters for ST\n\t\t\tif (this.useStringDelimiters) {\n\t\t\t\tprocessedTemplate = convertStringDelimitersToChar(template);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// For single-char delimiters, protect JSON content to avoid conflicts\n\t\t\t\tprocessedTemplate = protectJsonContent(template);\n\t\t\t}\n\t\t\tSTGroup group = new STGroup(this.startDelimiterToken, this.endDelimiterToken);\n\t\t\tgroup.setListener(new Slf4jStErrorListener(logger));\n\t\t\treturn new ST(group, processedTemplate);\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// Temporary placeholders for JSON braces\n\tprivate static final String JSON_OPEN_PLACEHOLDER = \"\\uE000\";\n\tprivate static final String JSON_CLOSE_PLACEHOLDER = \"\\uE001\";\n\n\t/**\n\t * Protects JSON content in templates when using single-character delimiters.\n\t * This method identifies JSON objects/arrays and replaces their braces with placeholders\n\t * to prevent StringTemplate from treating them as template variables.\n\t * @param template the original template\n\t * @return template with JSON braces protected\n\t */\n\tprivate String protectJsonContent(String template) {\n\t\tStringBuilder result = new StringBuilder();\n\t\tint i = 0;\n\t\tint len = template.length();","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/renderer/SaaStTemplateRenderer.java#L147-L183","documentation":"SaaStTemplateRenderer.createST() wraps StringTemplate (ST) construction in a catch-all that rethrows any parsing/processing failure as IllegalArgumentException(\"The template string is not valid.\", ex). The template text could not be turned into a valid ST instance with the configured delimiters.","triggerScenarios":"Calling the renderer with a template containing malformed ST syntax, unbalanced/unknown delimiters (custom start/end tokens), or characters that break ST parsing; nested braces from JSON conflicting with delimiters.","commonSituations":"Prompts containing JSON or code with { } colliding with the '{' '}' delimiter tokens; typos like unclosed '{name'; using a delimiter character that appears literally in the prompt; template loaded from config/user input with syntax errors.","solutions":["Fix the template syntax: close all '{var}' expressions and escape literal delimiters","Check the rendered output — the cause (ex.getCause()) names the exact ST syntax problem","Use the renderer's JSON placeholder handling or choose delimiters that don't collide with prompt content (e.g. '<' '>' or '$' '$')","Validate templates at startup with a dry-run render instead of failing at request time"],"exampleFix":"// before\nrenderer.render(\"User data: { \\\"name\\\": \\\"bob\\\" }\"); // { } collide with delimiters\n// after\nSaaStTemplateRenderer.builder()\n    .startDelimiterToken(\"$\").endDelimiterToken(\"$\")\n    .build();\n// template: \"User data: { \\\"name\\\": \\\"bob\\\" }, hello $name$\"","handlingStrategy":"try-catch","validationCode":"boolean templateParses(String tpl) { try { new STGroupDelim().InstanceOf(new STGroup('{','}'), tpl); return true; } catch (Exception e) { return false; } }","typeGuard":"boolean isRenderable(String tpl) { return tpl != null && tpl.chars().filter(c -> c == '{').count() == tpl.chars().filter(c -> c == '}').count(); }","tryCatchPattern":"try { renderer.apply(template, vars); } catch (IllegalArgumentException e) { log.error(\"Bad template syntax: {}\", e.getCause() != null ? e.getCause().getMessage() : e.getMessage()); throw new TemplateSyntaxException(template, e); }","preventionTips":["Inspect the wrapped cause — ST reports the exact syntax position","Escape or placeholder JSON braces that collide with the configured delimiters","Pick non-colliding delimiters for prompts containing raw JSON/code","Dry-run render all prompt templates at application startup"],"tags":["java","template","stringtemplate","prompt"],"backgroundTag":"invalid-argument-format","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}