spring-projects/spring-framework · error · AopConfigException

Unknown advisor type {}; can only include Advisor or Advice

Error message

Unknown advisor type {}; 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

Thrown as AopConfigException (wrapping UnknownAdviceTypeException) by ProxyFactoryBean.namedBeanToAdvisor when an entry in interceptorNames points to a bean that is neither an Advice nor an Advisor, AND it is not allowed to be the target (i.e., targetName/targetSource was already set, or it is not the last entry). Spring expected every non-final name to be an Advice/Advisor.

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 69bf83ad71)

Solutions

  1. Move the target bean out of interceptorNames and use the targetName/target property instead.
  2. Ensure every entry in interceptorNames (except optionally the last) is a bean of type Advice or Advisor.
  3. If the last entry is meant to be the target, do NOT also set targetName/targetSource (the factory only allows one target style).
  4. Check bean type with beanFactory.getType(name) — it must be assignable to Advice or Advisor (or be the legitimate final target).

Example fix

<!-- before -->
<bean id="p" class="...ProxyFactoryBean">
  <property name="targetName" value="svc"/>
  <property name="interceptorNames"><list><value>svc</value><value>loggingAdvice</value></list></property>
</bean>

<!-- after -->
<bean id="p" class="...ProxyFactoryBean">
  <property name="targetName" value="svc"/>
  <property name="interceptorNames"><list><value>loggingAdvice</value></list></property>
</bean>
Defensive patterns

Strategy: validation

Validate before calling

// Verify each non-final interceptor name is Advice/Advisor
BeanFactory bf = ...;
String[] names = pfb.getInterceptorNames();
for (int i = 0; i < names.length; i++) {
  Class<?> t = bf.getType(names[i]);
  boolean isAdvice = t != null && (Advice.class.isAssignableFrom(t) || Advisor.class.isAssignableFrom(t));
  if (!isAdvice && i < names.length - 1) throw new IllegalStateException(names[i] + " is not Advice/Advisor");
}

Type guard

static boolean isAdviceOrAdvisorBean(BeanFactory bf, String name) {
  Class<?> t = bf.getType(name);
  return t != null && (Advice.class.isAssignableFrom(t) || Advisor.class.isAssignableFrom(t));
}

Try / catch

try { Object p = pfb.getObject(); }
catch (AopConfigException e) {
  if (e.getMessage().contains("Unknown advisor type")) { /* move target out of interceptorNames */ }
  throw e;
}

Prevention

When it happens

Trigger: interceptorNames references a plain service/POJO bean in a position that is not the final one, or the target is already set via targetName so even the last entry must be an Advice/Advisor. The advisorAdapterRegistry.wrap call at line 553 throws UnknownAdviceTypeException, rethrown here as AopConfigException with the explanatory message.

Common situations: Listing the target bean in the middle of interceptorNames by mistake; using a target bean name that is shared with another non-advice bean; renaming an advice bean and forgetting to update interceptorNames; mixing targetName property with a target-as-last-entry style (now the last entry is treated as advice and fails).

Related errors


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