spring-projects/spring-framework · error · NotAnAtAspectException
{aspectClass.getName()} is not an @AspectJ aspect
Error message
{aspectClass.getName()} is not an @AspectJ aspect What it means
Thrown by AbstractAspectJAdvisorFactory.validate() as a NotAnAtAspectException (subclass of AopConfigException) when the supplied class is not recognized as an AspectJ aspect by the AjType reflection API (i.e., it lacks the @Aspect annotation, or that annotation is not meta-present). Spring AOP can only build advisors from classes that AspectJ considers aspects, so this guard prevents downstream advisor generation from operating on a non-aspect. The exception exposes getNonAspectClass() for programmatic handling. It is distinct from the AspectMetadata/AspectJProxyFactory variants in that it originates in the shared validate(Class) entry point invoked by ReflectiveAspectJAdvisorFactory before getAdvisors()/getAdvice().
Source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java:97
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
protected final ParameterNameDiscoverer parameterNameDiscoverer = new AspectJAnnotationParameterNameDiscoverer();
@Override
public boolean isAspect(Class<?> clazz) {
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null &&
(!shouldIgnoreAjcCompiledAspects || !compiledByAjc(clazz)));
}
@Override
public void validate(Class<?> aspectClass) throws AopConfigException {
AjType<?> ajType = AjTypeSystem.getAjType(aspectClass);
if (!ajType.isAspect()) {
throw new NotAnAtAspectException(aspectClass);
}
if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOW) {
throw new AopConfigException(aspectClass.getName() + " uses percflow instantiation model: " +
"This is not supported in Spring AOP.");
}
if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOWBELOW) {
throw new AopConfigException(aspectClass.getName() + " uses percflowbelow instantiation model: " +
"This is not supported in Spring AOP.");
}
}
/**
* Find and return the first AspectJ annotation on the given method
* (there <i>should</i> only be one anyway...).
*/
@SuppressWarnings("unchecked")
protected static @Nullable AspectJAnnotation findAspectJAnnotationOnMethod(Method method) {View on GitHub (pinned to 69bf83ad71)
Solutions
- Annotate the class with @org.aspectj.lang.annotation.Aspect (verify the package is org.aspectj.lang.annotation, not a custom one).
- Confirm the class is concrete (or abstract for shared pointcut base) and that @Aspect is retained at runtime (it has RUNTIME retention by default).
- If using @AspectJ auto-proxying, ensure the aspect bean is component-scanned or declared as a @Bean and that no beanFactory.getType(beanName) returns null or a proxy placeholder.
- If the aspect is ajc-compiled and double-proxying occurs, set spring.aop.ajc.ignore=true only as a last resort (restructure the AspectJ config instead).
Example fix
// before
public class LoggingAdvice {
@Before("execution(* com.example.*.*(..))")
public void before() { ... }
}
// after
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class LoggingAdvice {
@Before("execution(* com.example.*.*(..))")
public void before() { ... }
} Defensive patterns
Strategy: validation
Validate before calling
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.AnnotationUtils;
public static boolean isAtAspect(Class<?> clazz) {
return AnnotationUtils.findAnnotation(clazz, Aspect.class) != null;
}
// before calling factory.validate(clazz) or getAdvisors(...):
if (!isAtAspect(MyAspect.class)) {
throw new IllegalStateException("Class is not an @AspectJ aspect; annotate it with @Aspect");
} Type guard
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.AjTypeSystem;
public static boolean isAspectJAspect(Class<?> candidate) {
return AjTypeSystem.getAjType(candidate).isAspect();
} Try / catch
try {
advisorFactory.validate(aspectClass);
} catch (NotAnAtAspectException ex) {
// ex.getNonAspectClass() gives the offending class
log.warn("Skipping non-aspect {}", ex.getNonAspectClass().getName());
} Prevention
- Centralize aspect classes in a dedicated package and enforce @Aspect via a (e.g.) ArchUnit or custom Checkstyle rule.
- In code review, verify every class containing @Before/@Around/@After also carries @Aspect.
- Add a smoke test that loads all aspect beans and asserts advisorFactory.isAspect(type) is true.
When it happens
Trigger: Calling AspectJAdvisorFactory.validate(class), getAdvisors(factory), or getAdvice(...) where the aspect class has no @Aspect annotation; using @AspectJ auto-proxying (@EnableAspectJAutoProxy) where a bean in the context is passed to the factory but its Class lacks org.aspectj.lang.annotation.Aspect; programmatically invoking new ReflectiveAspectJAdvisorFactory().getAdvisors(factoryInstance) on a MetadataAwareAspectInstanceFactory whose aspectClass is a plain POJO. Also triggered if @Aspect is imported from the wrong package or is a custom annotation not meta-annotated with @Aspect.
Common situations: Forgetting the @Aspect annotation on a class containing @Before/@Around advice methods; accidentally importing a different Aspect annotation (e.g., a project-local annotation of the same simple name); removing @Aspect during a refactor; annotating an interface instead of a class; aspect class loaded with ajc weaving but the @Aspect annotation stripped by a classloader/shading plugin; mixing up the target class vs the aspect class in AspectJProxyFactory.addAspect(Class).
Related errors
- Advice must be declared inside an aspect type: Offending met
- 'argumentNames' property of AbstractAspectJAdvice contains a
- Only afterReturning advice can be used to bind a return valu
- Only afterThrowing advice can be used to bind a thrown excep
- Expecting to find {} arguments to bind by name in advice, bu
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/3f78f2dd4308d901.
Report an issue: GitHub.