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
- Verify each non-final interceptorNames entry implements Advisor, MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice, or ThrowsAdvice.
- Ensure the target bean is the LAST entry in interceptorNames (or use target/targetName instead).
- 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
- Keep the target as the LAST entry of interceptorNames, or use target/targetName.
- Use beanFactory.getType(name) to pre-check each non-final entry implements Advice/Advisor.
- Register custom AdvisorAdapters for non-standard advice types.
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
- Target required after globals
- Advice object [{adviceObject}] is neither a supported subint
- Advice must be declared inside an aspect type: Offending met
- Unknown advice kind [{}].
- DynamicIntroductionAdvice may only be added as part of Intro
AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04).
Data as JSON: /data/errors/3149830ab074eb2d.json.
Report an issue: GitHub.