spring-projects/spring-framework · error · IllegalArgumentException
Class '{aspectClass.getName()}' is not an @AspectJ aspect
Error message
Class '{aspectClass.getName()}' is not an @AspectJ aspect What it means
Thrown as an IllegalArgumentException from the AspectMetadata constructor when walking the class hierarchy (the aspect class and all superclasses up to Object) finds no class whose AjType.isAspect() is true. Unlike AbstractAspectJAdvisorFactory.validate (which only checks the exact class via AjTypeSystem), AspectMetadata walks superclasses, so this fires only when neither the class nor any ancestor is an aspect.
Source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java:95
* Create a new AspectMetadata instance for the given aspect class.
* @param aspectClass the aspect class
* @param aspectName the name of the aspect
*/
public AspectMetadata(Class<?> aspectClass, String aspectName) {
this.aspectName = aspectName;
Class<?> currClass = aspectClass;
AjType<?> ajType = null;
while (currClass != Object.class) {
AjType<?> ajTypeToCheck = AjTypeSystem.getAjType(currClass);
if (ajTypeToCheck.isAspect()) {
ajType = ajTypeToCheck;
break;
}
currClass = currClass.getSuperclass();
}
if (ajType == null) {
throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect");
}
if (ajType.getDeclarePrecedence().length > 0) {
throw new IllegalArgumentException("DeclarePrecedence not presently supported in Spring AOP");
}
this.aspectClass = ajType.getJavaClass();
this.ajType = ajType;
switch (this.ajType.getPerClause().getKind()) {
case SINGLETON -> {
this.perClausePointcut = Pointcut.TRUE;
}
case PERTARGET, PERTHIS -> {
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setLocation(aspectClass.getName());
ajexp.setExpression(findPerClause(aspectClass));
ajexp.setPointcutDeclarationScope(aspectClass);
this.perClausePointcut = ajexp;
}View on GitHub (pinned to 69bf83ad71)
Solutions
- Ensure the class (or a superclass) carries @org.aspectj.lang.annotation.Aspect with RUNTIME retention.
- Verify classloader visibility: the @Aspect annotation type and the aspect class must be loaded by the same or ancestor classloader as Spring.
- If extending an abstract aspect base, confirm the base class is annotated @Aspect and is on the classpath at runtime.
Example fix
// before
public class TxAdvice { ... }
new AspectMetadata(TxAdvice.class, "txAdvice"); // throws
// after
@Aspect
public class TxAdvice {
@Around("execution(* com.example..*.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable { return pjp.proceed(); }
} Defensive patterns
Strategy: validation
Validate before calling
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.AjTypeSystem;
public static boolean hasAspectInHierarchy(Class<?> clazz) {
Class<?> c = clazz;
while (c != Object.class) {
if (AjTypeSystem.getAjType(c).isAspect()) return true;
c = c.getSuperclass();
}
return false;
}
// before new AspectMetadata(clazz, name):
if (!hasAspectInHierarchy(clazz)) {
throw new IllegalArgumentException(clazz + " is not an @AspectJ aspect");
} Type guard
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.AnnotationUtils;
public static boolean isAtAspectOrInherits(Class<?> c) {
return AnnotationUtils.findAnnotation(c, Aspect.class) != null;
} Try / catch
try {
AspectMetadata md = new AspectMetadata(clazz, name);
} catch (IllegalArgumentException ex) {
if (ex.getMessage().contains("not an @AspectJ aspect")) {
// annotate clazz (or a superclass) with @Aspect
} else throw ex;
} Prevention
- Ensure abstract aspect base classes carry @Aspect so subclasses inherit aspect status.
- Confirm @Aspect is on the runtime classpath for the context's classloader.
- Test aspect metadata construction for all aspect beans at startup.
When it happens
Trigger: Constructing new AspectMetadata(nonAspectClass, name) directly; indirectly via AspectJProxyFactory, BeanFactoryAspectJAdvisorsBuilder, or any MetadataAwareAspectInstanceFactory when the supplied class (and all its supertypes) lacks @Aspect.
Common situations: Supplying a plain bean class to a metadata-driven aspect factory; an aspect base class annotated @Aspect that was loaded by a different classloader so the annotation is invisible; passing an interface or proxy class; stale bytecode where @Aspect was removed.
Related errors
- '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
- Not enough arguments in method to satisfy binding of returni
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/2d1e05eecdb6998d.
Report an issue: GitHub.