spring-projects/spring-framework · error · IllegalArgumentException
Throwing name ' ' is neither a valid argument name nor the…
Error message
Throwing name '{}' is neither a valid argument name nor the fully-qualified name of a Java type on the classpath. Root cause: {} What it means
Thrown by setThrowingNameNoCheck (line 333-348) when the throwing value is neither a Java variable name (fails isVariableName) nor resolvable as a fully-qualified type via ClassUtils.forName on the aspect class loader. In type form it restricts which exception types trigger the advice; in variable form it binds the thrown exception. Failure of both means binding cannot proceed.
Solutions
- If you meant a variable name, use a valid Java identifier matching an advice parameter of a Throwable subtype (e.g. throwing="ex").
- If you meant a type restriction, use the exact fully-qualified exception name and confirm it is visible to getAspectClassLoader().
- Read the root cause (usually ClassNotFoundException) in the message to locate the missing type.
- Rebuild/redeploy so the exception class is on the runtime classpath.
Example fix
// before — misspelled exception type
@AfterThrowing(pointcut="execution(* svc.*(..))", throwing="java.lang.RuntimeErr")
public void onError(Throwable t) {}
// after — valid variable name bound to the advice parameter
@AfterThrowing(pointcut="execution(* svc.*(..))", throwing="t")
public void onError(Throwable t) {} Defensive patterns
Strategy: validation
Validate before calling
import org.springframework.util.ClassUtils;
void safeSetThrowingName(AbstractAspectJAdvice advice, String name) {
if (isJavaIdentifier(name) || isLoadableType(name, advice.getAspectClassLoader())) {
advice.setThrowingName(name); // routed to the afterThrowing subclass
} else {
throw new IllegalArgumentException("throwing '" + name + "' is neither identifier nor loadable type");
}
}
boolean isLoadableType(String name, ClassLoader cl) {
try { ClassUtils.forName(name, cl); return true; } catch (Throwable t) { return false; }
} Type guard
boolean isThrowingNameValid(String name, ClassLoader cl) {
if (name == null) return false;
if (Character.isJavaIdentifierStart(name.charAt(0))) {
return name.chars().skip(1).allMatch(Character::isJavaIdentifierPart);
}
try { Class.forName(name, false, cl); return true; } catch (Throwable t) { return false; }
} Try / catch
try {
((AspectJAfterThrowingAdvice) advice).setThrowingName(name);
} catch (IllegalArgumentException ex) {
// root cause is usually ClassNotFoundException; correct the name/classpath
} Prevention
- Prefer a variable name bound to a Throwable parameter over a type restriction.
- Ensure the exception class jar is on the aspect class loader.
- Update the throwing attribute when exception packages change.
When it happens
Trigger: Setting throwing="java.io.NonexistentException" where the type is not on the classpath, or throwing="err-code" (neither identifier nor type). Occurs via XML 'throwing' attribute or @AfterThrowing(throwing=...) when the value is wrong.
Common situations: Misspelled exception class name, a custom exception class in a jar not loaded by the aspect class loader, or using a non-identifier string as the throwing name. Common after moving exception classes between packages.
Related errors
- Binding of throwing parameter
- Returning name ' ' is neither a valid argument name nor the…
- Throwing argument name
- Advice method [ ] requires arguments to be bound by name…
- 'argumentNames' property of AbstractAspectJAdvice contains…
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/f59a4db5f7231f69.
Report an issue: GitHub.
Appendix: source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java:344
throw new UnsupportedOperationException("Only afterThrowing advice can be used to bind a thrown exception");
}
/**
* We need to hold the throwing name at this level for argument binding calculations,
* this method allows the afterThrowing advice subclass to set the name.
*/
protected void setThrowingNameNoCheck(String name) {
// name could be a variable or a type...
if (isVariableName(name)) {
this.throwingName = name;
}
else {
// assume a type
try {
this.discoveredThrowingType = ClassUtils.forName(name, getAspectClassLoader());
}
catch (Throwable ex) {
throw new IllegalArgumentException("Throwing name '" + name +
"' is neither a valid argument name nor the fully-qualified " +
"name of a Java type on the classpath. Root cause: " + ex);
}
}
}
protected Class<?> getDiscoveredThrowingType() {
return this.discoveredThrowingType;
}
@Contract("null -> false")
private static boolean isVariableName(@Nullable String name) {
return AspectJProxyUtils.isVariableName(name);
}
/**
* Do as much work as we can as part of the set-up so that argument bindingView on GitHub (pinned to 69bf83ad71)