alibaba/spring-ai-alibaba · error · IllegalStateException
Not all variables were replaced in the template. Missing…
Error message
Not all variables were replaced in the template. Missing variable names are: %s.
What it means
SaaStTemplateRenderer.validate() compares template variables against the supplied inputs; when variables remain unbound and validationMode is THROW, it throws IllegalStateException listing the missing names. (In WARN mode it only logs.) This guards against silently rendering prompts with unfilled placeholders.
Solutions
- Supply values for every listed missing variable name (the message names them exactly)
- Switch the renderer to ValidationMode.WARN or IGNORE if unfilled placeholders are acceptable
- Align the prompt template and the code that fills it — remove unused placeholders or add the keys
- Default the variables map so optional placeholders always have a value
Example fix
// before
Map.of("query", userQuery); // template also needs $tools$
// after
Map.of("query", userQuery, "tools", toolDescriptions); Defensive patterns
Strategy: try-catch
Validate before calling
Set<String> missing = renderer.validate(template, vars); if (!missing.isEmpty()) throw new IllegalStateException("Missing template variables: " + missing); Try / catch
try { prompt = renderer.apply(template, vars); } catch (IllegalStateException e) { log.error("Unfilled template variables: {}", e.getMessage()); vars = fillDefaults(vars); prompt = renderer.apply(template, vars); } Prevention
- Read the error message — it lists the exact missing variable names
- Keep the prompt template and its filling code in sync (review them together)
- Use ValidationMode.WARN during development to spot drift early
- Provide defaults for optional placeholders in the variables map
When it happens
Trigger: Applying a template whose placeholders (e.g. $tools$, $query$) have no matching keys in the variables map, with ValidationMode.THROW configured.
Common situations: Renaming a prompt placeholder without updating the caller's variable map; supplying variables under different key casing/names; conditional placeholders that are only sometimes filled; prompt template updated independently of code.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- The template string is not valid.
- At least one fallback model must be specified
- Either skill_name or skill_path is required
- Elastic search index name must be provided
- Invalid experiment status
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/d5406e2b56f987fc.
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:462
/**
* Validates that all required template variables are provided in the model. Returns
* the set of missing variables for further handling or logging.
* @param st the StringTemplate instance
* @param templateVariables the provided variables
* @return set of missing variable names, or empty set if none are missing
*/
private Set<String> validate(ST st, Map<String, Object> templateVariables) {
Set<String> templateTokens = getInputVariables(st);
Set<String> modelKeys = templateVariables.keySet();
Set<String> missingVariables = new HashSet<>(templateTokens);
missingVariables.removeAll(modelKeys);
if (!missingVariables.isEmpty()) {
if (this.validationMode == ValidationMode.WARN) {
logger.warn(VALIDATION_MESSAGE.formatted(missingVariables));
}
else if (this.validationMode == ValidationMode.THROW) {
throw new IllegalStateException(VALIDATION_MESSAGE.formatted(missingVariables));
}
}
return missingVariables;
}
private Set<String> getInputVariables(ST st) {
TokenStream tokens = st.impl.tokens;
Set<String> inputVariables = new HashSet<>();
boolean isInsideList = false;
for (int i = 0; i < tokens.size(); i++) {
Token token = tokens.get(i);
// Handle list variables with option (e.g., {items; separator=", "})
if (token.getType() == STLexer.LDELIM && i + 1 < tokens.size()
&& tokens.get(i + 1).getType() == STLexer.ID) {
if (i + 2 < tokens.size() && tokens.get(i + 2).getType() == STLexer.COLON) {
String text = tokens.get(i + 1).getText();View on GitHub (pinned to f82da0b50f)