spring-projects/spring-framework · error · UnsupportedOperationException

Only afterThrowing advice can be used to bind a thrown…

Error message

Only afterThrowing advice can be used to bind a thrown exception

What it means

The base AbstractAspectJAdvice.setThrowingName(String) at line 325-327 always throws UnsupportedOperationException. Only AspectJAfterThrowingAdvice overrides it to delegate to setThrowingNameNoCheck. Binding a thrown exception is semantically valid only for after-throwing advice, so every other advice type refuses it.

Solutions

  1. Move the 'throwing' binding to an @AfterThrowing / <aop:after-throwing> advice — the only type that supports it.
  2. Remove the 'throwing' attribute from the offending before/around/after-returning element.
  3. If registering programmatically, guard setThrowingName with an instanceof AspectJAfterThrowingAdvice check.

Example fix

// before — throwing on after-returning (invalid)
<aop:after-returning method="after"
    pointcut="execution(* *(..))" throwing="ex"/>

// after — use after-throwing advice to bind the exception
<aop:after-throwing method="onError"
    pointcut="execution(* *(..))" throwing="ex"/>
Defensive patterns

Strategy: type-guard

Validate before calling

import org.springframework.aop.aspectj.AspectJAfterThrowingAdvice;

void safeSetThrowingName(AbstractAspectJAdvice advice, String name) {
    if (advice instanceof AspectJAfterThrowingAdvice) {
        advice.setThrowingName(name);
    } else {
        throw new IllegalStateException("throwing binding requires AspectJAfterThrowingAdvice");
    }
}

Type guard

boolean supportsThrowingBinding(AbstractAspectJAdvice advice) {
    return advice instanceof org.springframework.aop.aspectj.AspectJAfterThrowingAdvice;
}

Try / catch

try {
    advice.setThrowingName("ex");
} catch (UnsupportedOperationException ex) {
    // throwing is only valid for afterThrowing advice; remove the attribute
}

Prevention

When it happens

Trigger: Calling setThrowingName("ex") on an instance of AspectJMethodBeforeAdvice, AspectJAroundAdvice, or AspectJAfterReturningAdvice, or configuring a 'throwing' attribute on <aop:before>, <aop:around>, or <aop:after-returning>. Also triggered by a generic programmatic registrar that always sets throwing.

Common situations: XML/annotation config where a 'throwing="..."' attribute lands on the wrong advice element, or a shared advisor builder that unconditionally calls setThrowingName. Typical when copying an after-throwing block and forgetting to change the advice kind.

Related errors


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

Appendix: source

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

			}
			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");
	}

	/**
	 * 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 +

View on GitHub (pinned to 69bf83ad71)