spring-projects/spring-framework · error · IllegalArgumentException

Returning name ' ' is neither a valid argument name nor the…

Error message

Returning 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 setReturningNameNoCheck (line 299-314) when the returning value is neither a Java variable name (fails isVariableName) nor resolvable as a fully-qualified type via ClassUtils.forName using the aspect class loader. In the type form, Spring restricts the matched return type; in the variable form, it binds the actual return value. If neither interpretation works, binding is impossible.

Solutions

  1. If you meant a variable name, use a valid Java identifier matching an advice parameter (e.g. returning="retVal").
  2. If you meant a type restriction, use the exact fully-qualified name and verify the class is on the aspect class loader (getAspectClassLoader()).
  3. Check the root cause in the message — it typically contains a ClassNotFoundException naming the misspelled/missing type.
  4. Ensure the jar containing the type is on the runtime classpath and not shaded out.

Example fix

// before — misspelled package
@AfterReturning(pointcut="execution(* svc.*(..))", returning="com.exmaple.Result")
public void after(Object r) {}

// after — valid variable name binding to the advice parameter
@AfterReturning(pointcut="execution(* svc.*(..))", returning="r")
public void after(Object r) {}
Defensive patterns

Strategy: validation

Validate before calling

import org.springframework.util.ClassUtils;

// Validate that 'returning' is either an identifier or a resolvable type before setting.
void safeSetReturningName(AbstractAspectJAdvice advice, String name) {
    if (isJavaIdentifier(name) || isLoadableType(name, advice.getAspectClassLoader())) {
        advice.setReturningName(name); // routed to the afterReturning subclass
    } else {
        throw new IllegalArgumentException("returning '" + 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 isReturningNameValid(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 {
    ((AspectJAfterReturningAdvice) advice).setReturningName(name);
} catch (IllegalArgumentException ex) {
    // check root cause for ClassNotFoundException; fix the type/identifier
}

Prevention

When it happens

Trigger: Setting returning="com.example.UnknownType" where the type is not on the aspect's classpath, or returning="123bad" / returning="return-value" (not an identifier and not a type). Occurs via XML 'returning' attribute or @AfterReturning(returning=...) when the supplied value is misspelled.

Common situations: Misspelled fully-qualified class name in the returning attribute, a return type that lives in a module/jar not visible to the aspect class loader, or using a hyphenated/illegal identifier as the returning name. Common after refactoring that renames the bound type without updating the aspect XML/annotation.

Related errors


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

Appendix: source

Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java:310

		throw new UnsupportedOperationException("Only afterReturning advice can be used to bind a return value");
	}

	/**
	 * We need to hold the returning name at this level for argument binding calculations,
	 * this method allows the afterReturning advice subclass to set the name.
	 */
	protected void setReturningNameNoCheck(String name) {
		// name could be a variable or a type...
		if (isVariableName(name)) {
			this.returningName = name;
		}
		else {
			// assume a type
			try {
				this.discoveredReturningType = ClassUtils.forName(name, getAspectClassLoader());
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException("Returning 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<?> getDiscoveredReturningType() {
		return this.discoveredReturningType;
	}

	protected @Nullable Type getDiscoveredReturningGenericType() {
		return this.discoveredReturningGenericType;
	}

	public void setThrowingName(String name) {
		throw new UnsupportedOperationException("Only afterThrowing advice can be used to bind a thrown exception");
	}

View on GitHub (pinned to 69bf83ad71)