spring-projects/spring-framework · error · AopConfigException

DynamicIntroductionAdvice may only be added as part of…

Error message

DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor

What it means

addAdvice(int, Advice) (line 435) handles three branches: IntroductionInfo (self-describing), DynamicIntroductionAdvice, and plain advice. A DynamicIntroductionAdvice (e.g. a per-instance introduction mixin) carries introduction state and must be registered through an IntroductionAdvisor so its interfaces are validated and added. Registering it as plain advice is rejected (line 444).

Solutions

  1. Wrap the introduction advice in an IntroductionAdvisor: advised.addAdvisor(new DefaultIntroductionAdvisor(advice, introductionInfo))
  2. If the advice implements IntroductionInfo too, addAdvice can work via that branch - otherwise always use an IntroductionAdvisor
  3. Review the advice type: anything that is a DynamicIntroductionAdvice must go through an advisor

Example fix

// before
advised.addAdvice(myDelegatingIntroductionInterceptor);

// after
advised.addAdvisor(new DefaultIntroductionAdvisor(myDelegatingIntroductionInterceptor));
Defensive patterns

Strategy: type-guard

Validate before calling

if (advice instanceof DynamicIntroductionAdvice) {
  throw new IllegalStateException("Use addAdvisor(new DefaultIntroductionAdvisor(advice)) for introduction advice");
}

Type guard

private static boolean isPlainAdvice(Advice advice) {
  return advice != null && !(advice instanceof DynamicIntroductionAdvice);
}

Prevention

When it happens

Trigger: Passing an instance whose class implements org.springframework.aop.DynamicIntroductionAdvice to addAdvice() directly, instead of wrapping it in an IntroductionAdvisor (e.g. DefaultIntroductionAdvisor).

Common situations: Trying to add a DelegatingIntroductionInterceptor or similar mixin via addAdvice(...) rather than addAdvisor(new DefaultIntroductionAdvisor(advice)); mixing up the addAdvice and addAdvisor entry points.

Related errors


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

Appendix: source

Thrown at spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java:444

	public void addAdvice(Advice advice) throws AopConfigException {
		int pos = this.advisors.size();
		addAdvice(pos, advice);
	}

	/**
	 * Cannot add introductions this way unless the advice implements IntroductionInfo.
	 */
	@Override
	public void addAdvice(int pos, Advice advice) throws AopConfigException {
		Assert.notNull(advice, "Advice must not be null");
		if (advice instanceof IntroductionInfo introductionInfo) {
			// We don't need an IntroductionAdvisor for this kind of introduction:
			// It's fully self-describing.
			addAdvisor(pos, new DefaultIntroductionAdvisor(advice, introductionInfo));
		}
		else if (advice instanceof DynamicIntroductionAdvice) {
			// We need an IntroductionAdvisor for this kind of introduction.
			throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
		}
		else {
			addAdvisor(pos, new DefaultPointcutAdvisor(advice));
		}
	}

	@Override
	public boolean removeAdvice(Advice advice) throws AopConfigException {
		int index = indexOf(advice);
		if (index == -1) {
			return false;
		}
		else {
			removeAdvisor(index);
			return true;
		}
	}

View on GitHub (pinned to 69bf83ad71)