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

  1. Supply values for every listed missing variable name (the message names them exactly)
  2. Switch the renderer to ValidationMode.WARN or IGNORE if unfilled placeholders are acceptable
  3. Align the prompt template and the code that fills it — remove unused placeholders or add the keys
  4. 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

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


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)