spring-projects/spring-framework · error · IllegalArgumentException
Aspect class [{}] does not define a singleton aspect
Error message
Aspect class [{}] does not define a singleton aspect What it means
Thrown by AspectJProxyFactory.addAspect(Object aspectInstance) when the supplied aspect instance's class does not declare a singleton per-clause (i.e. it is pertarget/perthis/pertypewithin/percflow/percflowbelow). addAspect(Object) requires a concrete singleton instance because the caller manages its lifecycle; non-singleton aspects must be added by class via addAspect(Class).
Source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectJProxyFactory.java:96
*/
public AspectJProxyFactory(Class<?>... interfaces) {
setInterfaces(interfaces);
}
/**
* Add the supplied aspect instance to the chain. The type of the aspect instance
* supplied must be a singleton aspect. True singleton lifecycle is not honored when
* using this method - the caller is responsible for managing the lifecycle of any
* aspects added in this way.
* @param aspectInstance the AspectJ aspect instance
*/
public void addAspect(Object aspectInstance) {
Class<?> aspectClass = aspectInstance.getClass();
String aspectName = aspectClass.getName();
AspectMetadata am = createAspectMetadata(aspectClass, aspectName);
if (am.getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON) {
throw new IllegalArgumentException(
"Aspect class [" + aspectClass.getName() + "] does not define a singleton aspect");
}
addAdvisorsFromAspectInstanceFactory(
new SingletonMetadataAwareAspectInstanceFactory(aspectInstance, aspectName));
}
/**
* Add an aspect of the supplied type to the end of the advice chain.
* @param aspectClass the AspectJ aspect class
*/
public void addAspect(Class<?> aspectClass) {
String aspectName = aspectClass.getName();
AspectMetadata am = createAspectMetadata(aspectClass, aspectName);
MetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectClass, aspectName);
addAdvisorsFromAspectInstanceFactory(instanceFactory);
}
View on GitHub (pinned to e8729d0438)
Solutions
- Switch to addAspect(MyAspect.class) so Spring creates per-target instances via a PrototypeAspectInstanceFactory.
- Change the aspect to singleton (remove the per-clause) if you want to keep passing an instance.
- Ensure the instance you pass is of a class annotated as a plain @Aspect (singleton).
Example fix
// before
factory.addAspect(new PerTargetAspect()); // @Aspect("pertarget(...)")
// after
factory.addAspect(PerTargetAspect.class); Defensive patterns
Strategy: validation
Validate before calling
import org.aspectj.lang.reflect.*;
boolean isSingletonAspect(Class<?> c) {
return AjTypeSystem.getAjType(c).getPerClause().getKind() == PerClauseKind.SINGLETON;
}
// before calling addAspect(instance):
if (!isSingletonAspect(instance.getClass())) {
// use addAspect(Class) instead
factory.addAspect(instance.getClass());
} else {
factory.addAspect(instance);
} Prevention
- Use addAspect(Class) for non-singleton aspects; reserve addAspect(Object) for singleton instances.
- Annotate per-clause aspects consistently and document which addAspect overload to use.
When it happens
Trigger: Calling new AspectJProxyFactory(target).addAspect(myAspectInstance) where myAspectInstance.getClass() is annotated @Aspect("pertarget(...)") or similar non-singleton per-clause.
Common situations: Passing a pre-built instance of a per-object aspect to AspectJProxyFactory. Confusing the two addAspect overloads — addAspect(Object) is singleton-only, addAspect(Class) supports non-singleton instantiation models.
Related errors
- {} uses percflow instantiation model: This is not supported
- {} uses percflowbelow instantiation model: This is not suppo
- Class [{}] is not a valid aspect type
- PerClause {} not supported by Spring AOP for {}
- MethodInvocation is not a Spring ProxyMethodInvocation: {}
AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04).
Data as JSON: /data/errors/3374365aab92c13e.json.
Report an issue: GitHub.