spring-projects/spring-framework · error · IllegalArgumentException

Placeholder [ ] is not valid

Error message

Placeholder [{match}] is not valid

What it means

Thrown by checkForInvalidPlaceholders (line 392-399) when a trace message template (enterMessage/exitMessage/exceptionMessage) set on CustomizableTraceInterceptor contains a placeholder token matching the regex $[Alpha]+ that is not in the ALLOWED_PLACEHOLDERS set. The interceptor only supports eight documented placeholders; any other token-shaped string is rejected as an IllegalArgumentException when the message is set.

Solutions

  1. Use only the documented placeholders: $[methodName], $[targetClassName], $[targetClassShortName], $[returnValue], $[argumentTypes], $[arguments], $[exception], $[invocationTime].
  2. Correct the typo - e.g. '$[return]' -> '$[returnValue]'.
  3. Mind per-message restrictions: enterMessage cannot contain $[returnValue], $[exception], or $[invocationTime]; these are checked separately after the placeholder check.
  4. Reference the PLACEHOLDER_* public constants when building the message string to avoid typos.

Example fix

// before
traceInterceptor.setExitMessage("Done $[method] in $[time] returned $[return]");

// after
traceInterceptor.setExitMessage(
    "Done $[methodName] in $[invocationTime] returned $[returnValue]");
Defensive patterns

Strategy: validation

Validate before calling

import org.springframework.aop.interceptor.CustomizableTraceInterceptor;
static void validateTemplate(String msg) {
    java.util.regex.Matcher m =
        java.util.regex.Pattern.compile("\\$\\[\\p{Alpha}+]").matcher(msg);
    while (m.find()) {
        if (!CustomizableTraceInterceptor.ALLOWED_PLACEHOLDERS.contains(m.group()))
            throw new IllegalArgumentException("Bad placeholder " + m.group());
    }
}

Prevention

When it happens

Trigger: Calling setEnterMessage, setExitMessage, or setExceptionMessage with a string containing a token like '$[method]', '$[return]', '$[time]', or '$[result]'. The regex PATTERN matches any $[letters]+ token, then ALLOWED_PLACEHOLDERS membership is checked - typos and unsupported names both fail.

Common situations: Misspelling a supported placeholder ($[returnValue] written as $[return]). Assuming a placeholder exists that does not (e.g. $[threadName]). Copying a template from another logging library's syntax into CustomizableTraceInterceptor.

Related errors


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/a63147d9a998af8a. Report an issue: GitHub.

Appendix: source

Thrown at spring-aop/src/main/java/org/springframework/aop/interceptor/CustomizableTraceInterceptor.java:397

		String[] argumentTypeShortNames = new String[argumentTypes.length];
		for (int i = 0; i < argumentTypeShortNames.length; i++) {
			argumentTypeShortNames[i] = ClassUtils.getShortName(argumentTypes[i]);
		}
		matcher.appendReplacement(output,
				Matcher.quoteReplacement(StringUtils.arrayToCommaDelimitedString(argumentTypeShortNames)));
	}

	/**
	 * Checks to see if the supplied {@code String} has any placeholders
	 * that are not specified as constants on this class and throws an
	 * {@code IllegalArgumentException} if so.
	 */
	private static void checkForInvalidPlaceholders(String message) throws IllegalArgumentException {
		Matcher matcher = PATTERN.matcher(message);
		while (matcher.find()) {
			String match = matcher.group();
			if (!ALLOWED_PLACEHOLDERS.contains(match)) {
				throw new IllegalArgumentException("Placeholder [" + match + "] is not valid");
			}
		}
	}

}

View on GitHub (pinned to 69bf83ad71)