spring-projects/spring-framework · error · IllegalArgumentException
'argumentNames' property of AbstractAspectJAdvice contains…
Error message
'argumentNames' property of AbstractAspectJAdvice contains an argument name '{}' that is not a valid Java identifier What it means
Thrown by setArgumentNamesFromStringArray (line 262-272) when one of the supplied argument names fails the isVariableName check (delegated to AspectJProxyUtils.isVariableName, which requires a valid Java identifier). The argument names are later used to bind pointcut parameters to advice parameters, so Spring validates them eagerly rather than failing later during matching.
Solutions
- Inspect the offending token printed in the message and correct it to a valid Java identifier (letters, digits, underscore, $; not starting with a digit).
- Remove trailing/leading whitespace and stray commas from the arg-names string; StringUtils.commaDelimitedListToStringArray does not strip delimiters.
- Do not include the implicit thisJoinPoint / thisJoinPointStaticPart parameter in arg-names — Spring inserts 'THIS_JOIN_POINT' automatically when the parameter count is one greater (see lines 273-288).
- If you intended a type rather than a variable, use the returning/throwing attribute instead of arg-names.
Example fix
// before
<aop:after-returning method="after"
pointcut="execution(* *(..)) && args(payload)"
arg-names="payload,returning-val" returning="returning-val"/>
// after — use valid Java identifiers only, no hyphens
<aop:after-returning method="after"
pointcut="execution(* *(..)) && args(payload)"
arg-names="payload,returningVal" returning="returningVal"/> Defensive patterns
Strategy: validation
Validate before calling
// Validate arg-names tokens before passing to setArgumentNames.
import java.util.regex.Pattern;
private static final Pattern JAVA_IDENT = Pattern.compile("^[A-Za-z_$][A-Za-z0-9_$]*$");
void safeSetArgumentNames(AbstractAspectJAdvice advice, String argNames) {
for (String token : argNames.split(",")) {
String t = token.strip();
if (!JAVA_IDENT.matcher(t).matches()) {
throw new IllegalArgumentException("Invalid arg-name token: '" + t + "'");
}
}
advice.setArgumentNames(argNames);
} Type guard
boolean isValidArgName(String token) {
if (token == null || token.isBlank()) return false;
if (!Character.isJavaIdentifierStart(token.charAt(0))) return false;
for (int i = 1; i < token.length(); i++) {
if (!Character.isJavaIdentifierPart(token.charAt(i))) return false;
}
return true;
} Try / catch
try {
advice.setArgumentNames(argNames);
} catch (IllegalArgumentException ex) {
// log the offending token and surface a config-level error to the user
} Prevention
- Treat arg-names as bare Java identifiers; never put types or hyphenated names there.
- Strip and validate each token before calling setArgumentNames.
- Let Spring auto-insert the joinpoint slot — do not include it in arg-names.
When it happens
Trigger: Calling setArgumentNames("retVal, 1stArg") or passing a name with a space, dot, hyphen, leading digit, or empty string. Typically happens with XML <aop:aspect> 'arg-names' attributes containing typos, or programmatic registration of advice where arg-names is built by string concatenation.
Common situations: Typos in the XML arg-names attribute, copy-pasting a fully-qualified type name into arg-names (it expects bare variable names), trailing commas producing an empty token, or whitespace-only tokens after splitting. Also seen when someone puts the JoinPoint parameter name in the list manually with a non-identifier placeholder.
Related errors
- Expecting to find arguments to bind by name in advice, but…
- Not enough arguments in method to satisfy binding of…
- Advice method [ ] requires arguments to be bound by name…
- Advice must be declared inside an aspect type: Offending…
- is not an @AspectJ aspect
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/c6346c7b252b0cef.
Report an issue: GitHub.
Appendix: source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java:268
*/
public void setArgumentNames(String argumentNames) {
String[] tokens = StringUtils.commaDelimitedListToStringArray(argumentNames);
setArgumentNamesFromStringArray(tokens);
}
/**
* Set by the creator of this advice object if the argument names are known.
* <p>This could be for example because they have been explicitly specified in XML
* or in an advice annotation.
* @param argumentNames list of argument names
*/
public void setArgumentNamesFromStringArray(@Nullable String... argumentNames) {
this.argumentNames = new String[argumentNames.length];
for (int i = 0; i < argumentNames.length; i++) {
String argumentName = argumentNames[i];
this.argumentNames[i] = argumentName != null ? argumentName.strip() : null;
if (!isVariableName(this.argumentNames[i])) {
throw new IllegalArgumentException(
"'argumentNames' property of AbstractAspectJAdvice contains an argument name '" +
this.argumentNames[i] + "' that is not a valid Java identifier");
}
}
if (this.aspectJAdviceMethod.getParameterCount() == this.argumentNames.length + 1) {
// May need to add implicit join point arg name...
for (int i = 0; i < this.aspectJAdviceMethod.getParameterCount(); i++) {
Class<?> argType = this.aspectJAdviceMethod.getParameterTypes()[i];
if (argType == JoinPoint.class ||
argType == ProceedingJoinPoint.class ||
argType == JoinPoint.StaticPart.class) {
@Nullable String[] oldNames = this.argumentNames;
this.argumentNames = new String[oldNames.length + 1];
System.arraycopy(oldNames, 0, this.argumentNames, 0, i);
this.argumentNames[i] = "THIS_JOIN_POINT";
System.arraycopy(oldNames, i, this.argumentNames, i + 1, oldNames.length - i);
break;
}View on GitHub (pinned to 69bf83ad71)