spring-projects/spring-security · error · IllegalStateException

Unused placeholders in template

Error message

Unused placeholders in template: [%s]

What it means

HtmlTemplates.render validates that every {{placeholder}} in the template string is actually supplied by the caller's context. If any placeholder remains unreplaced after rendering (because no value was passed for it), rendering aborts with IllegalStateException listing the unused placeholders. This catches template/context mismatches early instead of shipping a page with literal {{...}} text.

Solutions

  1. Add the missing key/value to the context map passed to render
  2. Remove the {{placeholder}} from the template if it is no longer needed
  3. Fix key-name typos/casing so the placeholder matches a supplied key
  4. Ensure every code path rendering the template supplies all placeholders

Example fix

// before
HtmlTemplates.render("<h1>{{title}}</h1>{{subtitle}}", Map.of("title", "Hi"))
// after
HtmlTemplates.render("<h1>{{title}}</h1>{{subtitle}}", Map.of("title", "Hi", "subtitle", "Welcome"))
Defensive patterns

Strategy: validation

Validate before calling

// verify placeholders are covered before render
Set<String> placeholders = extractPlaceholders(template); // regex \{\{([a-zA-Z0-9]+)}}
if (!context.keySet().containsAll(placeholders)) {
    throw new IllegalArgumentException("Missing values: " + placeholders.removeAll(context.keySet()));
}

Try / catch

try {
    return HtmlTemplates.render(template, context);
} catch (IllegalStateException ex) {
    logger.error("Template mismatch: " + ex.getMessage());
    throw ex;
}

Prevention

When it happens

Trigger: Calling the public render(template, model/context) method where the template contains a {{name}} placeholder that has no corresponding key in the provided values map — e.g. a typo in the key name or a template updated without updating the caller.

Common situations: Editing an HTML template to add a new placeholder but forgetting to pass its value; passing context keys with wrong casing; reusing one template across code paths where one path omits a value.

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 spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/324ecc68e64bd1ca. Report an issue: GitHub.

Appendix: source

Thrown at web/src/main/java/org/springframework/security/web/server/ui/HtmlTemplates.java:100

		 * Render the template. All placeholders MUST have a corresponding value. If a
		 * placeholder does not have a corresponding value, throws
		 * {@link IllegalStateException}.
		 * @return the rendered template
		 */
		String render() {
			String template = this.template;
			for (String key : this.values.keySet()) {
				String pattern = "{{" + key + "}}";
				template = template.replace(pattern, this.values.get(key));
			}

			String unusedPlaceholders = Pattern.compile("\\{\\{([a-zA-Z0-9]+)}}")
				.matcher(template)
				.results()
				.map((result) -> result.group(1))
				.collect(Collectors.joining(", "));
			if (StringUtils.hasLength(unusedPlaceholders)) {
				throw new IllegalStateException("Unused placeholders in template: [%s]".formatted(unusedPlaceholders));
			}

			return template;
		}

	}

}

View on GitHub (pinned to 96852e8860)