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

  1. Annotate the class with @org.aspectj.lang.annotation.Aspect (verify the package is org.aspectj.lang.annotation, not a custom one).
  2. Confirm the class is concrete (or abstract for shared pointcut base) and that @Aspect is retained at runtime (it has RUNTIME retention by default).
  3. 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.
  4. 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

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


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