spring-projects/spring-framework · error · AopConfigException

Unknown advisor type {next.getClass()}; can only include Adv

Error message

Unknown advisor type {next.getClass()}; can only include Advisor or Advice type beans in interceptorNames chain except for last entry which may also be target instance or TargetSource

What it means

namedBeanToAdvisor() delegates to advisorAdapterRegistry.wrap(); if that throws UnknownAdviceTypeException (the bean is neither MethodInterceptor, nor a supported Advice like MethodBeforeAdvice/AfterReturningAdvice/ThrowsAdvice, nor an Advisor), ProxyFactoryBean wraps it as AopConfigException. The rule is: every interceptorNames entry must be an Advisor or Advice, except the LAST entry which may also be the target instance or a TargetSource.

Source

Thrown at spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java:558

				logger.debug("Refreshing target with name '" + this.targetName + "'");
			}
			Object target = this.beanFactory.getBean(this.targetName);
			return (target instanceof TargetSource targetSource ? targetSource : new SingletonTargetSource(target));
		}
	}

	/**
	 * Convert the following object sourced from calling getBean() on a name in the
	 * interceptorNames array to an Advisor or TargetSource.
	 */
	private Advisor namedBeanToAdvisor(Object next) {
		try {
			return this.advisorAdapterRegistry.wrap(next);
		}
		catch (UnknownAdviceTypeException ex) {
			// We expected this to be an Advisor or Advice,
			// but it wasn't. This is a configuration error.
			throw new AopConfigException("Unknown advisor type " + next.getClass() +
					"; can only include Advisor or Advice type beans in interceptorNames chain " +
					"except for last entry which may also be target instance or TargetSource", ex);
		}
	}

	/**
	 * Blow away and recache singleton on an advice change.
	 */
	@Override
	protected void adviceChanged() {
		super.adviceChanged();
		if (this.singleton) {
			logger.debug("Advice has changed; re-caching singleton instance");
			synchronized (this) {
				this.singletonInstance = null;
			}
		}
	}

View on GitHub (pinned to e8729d0438)

Solutions

  1. Verify each non-final interceptorNames entry implements Advisor, MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice, or ThrowsAdvice.
  2. Ensure the target bean is the LAST entry in interceptorNames (or use target/targetName instead).
  3. Register a custom AdvisorAdapter via AdvisorAdapterRegistry if using a non-standard Advice type.

Example fix

// before
<property name="interceptorNames" value="myTarget,myAdvice"/> <!-- target not last -->

// after
<property name="interceptorNames" value="myAdvice"/>
<property name="targetName" value="myTarget"/>
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate each named entry's type before adding to the chain
for (int i = 0; i < names.length; i++) {
    Class<?> type = beanFactory.getType(names[i]);
    boolean last = (i == names.length - 1);
    boolean ok = type != null &&
        (org.springframework.aop.Advisor.class.isAssignableFrom(type)
            || org.aopalliance.aop.Advice.class.isAssignableFrom(type)
            || (last && (org.springframework.aop.TargetSource.class.isAssignableFrom(type) || true)));
    if (!ok) throw new IllegalArgumentException("Entry '" + names[i] + "' is not Advisor/Advice" + (last ? " (or target)" : ""));
}

Type guard

public static boolean isAdviceOrAdvisor(Class<?> c) {
    return c != null && (org.springframework.aop.Advisor.class.isAssignableFrom(c)
        || org.aopalliance.aop.Advice.class.isAssignableFrom(c));
}

Try / catch

try {
    pfb.setInterceptorNames(names);
    return pfb.getObject();
} catch (AopConfigException ex) {
    if (ex.getMessage().contains("Unknown advisor type")) {
        throw new ConfigurationException("interceptorNames contains a non-advice bean; check ordering", ex);
    }
    throw ex;
}

Prevention

When it happens

Trigger: Listing a bean in interceptorNames (other than the final slot) whose type is a plain POJO with no AOP advice interface; accidentally putting the target in the middle of the chain; referencing an advice whose adapter was not registered.

Common situations: Misordering interceptorNames so the target is not last; bean type changed (refactor) so it no longer implements an advice interface; using a custom Advice type without registering a matching AdvisorAdapter.

Related errors


AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04). Data as JSON: /data/errors/3149830ab074eb2d.json. Report an issue: GitHub.