spring-projects/spring-framework · error · UnsupportedOperationException

Only afterReturning advice can be used to bind a return…

Error message

Only afterReturning advice can be used to bind a return value

What it means

The base AbstractAspectJAdvice.setReturningName(String) at line 291-293 always throws UnsupportedOperationException. Only AspectJAfterReturningAdvice overrides it to delegate to setReturningNameNoCheck. Binding a return value is semantically meaningless for before/around/after-throwing advice, so the base class forbids it.

Solutions

  1. Move the 'returning' binding to an @AfterReturning / <aop:after-returning> advice — it is the only advice type that supports it.
  2. If building advice programmatically, check the concrete type (instanceof AspectJAfterReturningAdvice) before calling setReturningName.
  3. Remove the 'returning' attribute from the offending before/around/after-throwing element.

Example fix

// before — returning on a before advice (invalid)
<aop:before method="check"
    pointcut="execution(* *(..))" returning="retVal"/>

// after — use after-returning advice to bind the return value
<aop:after-returning method="onSuccess"
    pointcut="execution(* *(..))" returning="retVal"/>
Defensive patterns

Strategy: type-guard

Validate before calling

import org.springframework.aop.aspectj.AspectJAfterReturningAdvice;

// Only call setReturningName on after-returning advice.
void safeSetReturningName(AbstractAspectJAdvice advice, String name) {
    if (advice instanceof AspectJAfterReturningAdvice) {
        advice.setReturningName(name);
    } else {
        throw new IllegalStateException("returning binding requires AspectJAfterReturningAdvice");
    }
}

Type guard

boolean supportsReturningBinding(AbstractAspectJAdvice advice) {
    return advice instanceof org.springframework.aop.aspectj.AspectJAfterReturningAdvice;
}

Try / catch

try {
    advice.setReturningName("retVal");
} catch (UnsupportedOperationException ex) {
    // returning is only valid for afterReturning advice; remove the attribute
}

Prevention

When it happens

Trigger: Calling setReturningName("retVal") on an instance of AspectJMethodBeforeAdvice, AspectJAroundAdvice, or AspectJAfterThrowingAdvice — or configuring a 'returning' attribute on an <aop:before>, <aop:around>, or <aop:after-throwing> element. Also triggered programmatically when reusing a generic advice-registration routine that always sets returning.

Common situations: XML config where a 'returning="..."' attribute is copy-pasted onto the wrong advice element, or a programmatic advisor builder that unconditionally calls setReturningName. Also happens when migrating an after-returning aspect to after-throwing without removing the returning clause.

Related errors


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

Appendix: source

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

			// 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;
				}
			}
		}
	}

	public void setReturningName(String name) {
		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 +

View on GitHub (pinned to 69bf83ad71)