alibaba/spring-ai-alibaba · error · IllegalArgumentException
The template string is not valid.
Error message
The template string is not valid.
What it means
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.
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
Example fix
// before
renderer.render("User data: { \"name\": \"bob\" }"); // { } collide with delimiters
// after
SaaStTemplateRenderer.builder()
.startDelimiterToken("$").endDelimiterToken("$")
.build();
// template: "User data: { \"name\": \"bob\" }, hello $name$" Defensive patterns
Strategy: try-catch
Validate before calling
boolean templateParses(String tpl) { try { new STGroupDelim().InstanceOf(new STGroup('{','}'), tpl); return true; } catch (Exception e) { return false; } } Type guard
boolean isRenderable(String tpl) { return tpl != null && tpl.chars().filter(c -> c == '{').count() == tpl.chars().filter(c -> c == '}').count(); } Try / catch
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); } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Not all variables were replaced in the template. Missing…
- 数据集版本数据量为0或不存在
- Agent not found:
- At least one fallback model must be specified
- At least one limit must be specified (threadLimit or…
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/057a7447dcdaf2b2.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/renderer/SaaStTemplateRenderer.java:165
}
private ST createST(String template) {
try {
String processedTemplate = template;
// If using string delimiters, convert them to single-char delimiters for ST
if (this.useStringDelimiters) {
processedTemplate = convertStringDelimitersToChar(template);
}
else {
// For single-char delimiters, protect JSON content to avoid conflicts
processedTemplate = protectJsonContent(template);
}
STGroup group = new STGroup(this.startDelimiterToken, this.endDelimiterToken);
group.setListener(new Slf4jStErrorListener(logger));
return new ST(group, processedTemplate);
}
catch (Exception ex) {
throw new IllegalArgumentException("The template string is not valid.", ex);
}
}
// Temporary placeholders for JSON braces
private static final String JSON_OPEN_PLACEHOLDER = "\uE000";
private static final String JSON_CLOSE_PLACEHOLDER = "\uE001";
/**
* Protects JSON content in templates when using single-character delimiters.
* This method identifies JSON objects/arrays and replaces their braces with placeholders
* to prevent StringTemplate from treating them as template variables.
* @param template the original template
* @return template with JSON braces protected
*/
private String protectJsonContent(String template) {
StringBuilder result = new StringBuilder();
int i = 0;
int len = template.length();View on GitHub (pinned to f82da0b50f)