spring-projects/spring-framework · error · AopConfigException
DynamicIntroductionAdvice may only be added as part of Intro
Error message
DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor
What it means
Thrown by AdvisedSupport.addAdvice(int, Advice) when the supplied Advice is a DynamicIntroductionAdvice but does not implement IntroductionInfo. Dynamic introductions (which add new interfaces/behavior to a target) require an IntroductionAdvisor to describe the interfaces being introduced, because the framework cannot infer them from a bare DynamicIntroductionAdvice. Spring routes self-describing IntroductionInfo instances through a DefaultIntroductionAdvisor automatically, but rejects bare DynamicIntroductionAdvice to avoid creating an incomplete introduction.
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 e8729d0438)
Solutions
- Wrap the DynamicIntroductionAdvice in a DefaultIntroductionAdvisor: new DefaultIntroductionAdvisor(advice, IntroductionInfo-implementation).
- Have your advice class implement IntroductionInfo (or DelegatingIntroductionInterceptor) so addAdvice can auto-wrap it.
- Use addAdvisor(new DefaultIntroductionAdvisor(...)) directly instead of addAdvice for introductions.
Example fix
// before DynamicIntroductionAdvice myIntro = ...; // no IntroductionInfo advised.addAdvice(myIntro); // throws // after import org.springframework.aop.support.DefaultIntroductionAdvisor; advised.addAdvisor(new DefaultIntroductionAdvisor(myIntro, MyInterface.class));
Defensive patterns
Strategy: type-guard
Type guard
static boolean needsIntroductionInfo(Advice advice) {
return advice instanceof org.springframework.aop.DynamicIntroductionAdvice
&& !(advice instanceof org.springframework.aop.IntroductionInfo);
} Prevention
- Implement IntroductionInfo (or extend DelegatingIntroductionInterceptor) on custom introduction advice.
- Wrap dynamic introductions in DefaultIntroductionAdvisor before adding.
- Use addAdvisor for introductions rather than addAdvice to make the contract explicit.
When it happens
Trigger: Passing a custom DynamicIntroductionAdvice implementation that implements neither IntroductionInfo nor is wrapped in an IntroductionAdvisor; using an old advice type that mixes introduction semantics without metadata.
Common situations: Authoring a custom mixin/introduction advice and forgetting to implement IntroductionInfo or to wrap it in DefaultIntroductionAdvisor; porting advice from frameworks that bundle introduction differently.
Related errors
- IntroductionInfo defines no interfaces to introduce: {introd
- DynamicIntroductionAdvice [{advice}] does not implement inte
- MethodInvocation is not a Spring ProxyMethodInvocation: {}
- 'argumentNames' property of AbstractAspectJAdvice contains a
- Only afterReturning advice can be used to bind a return valu
AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04).
Data as JSON: /data/errors/f758ec5beb859e92.json.
Report an issue: GitHub.