spring-projects/spring-framework · error · AopConfigException

uses percflow instantiation model: This is not supported in…

Error message

{aspectClass.getName()} uses percflow instantiation model: This is not supported in Spring AOP.

What it means

Thrown by AbstractAspectJAdvisorFactory.validate() as an AopConfigException when the aspect's per-clause kind is PerClauseKind.PERCFLOW. Spring AOP's proxy-based model only supports singleton, perthis, pertarget, and pertypewithin instantiation; percflow (one aspect instance per flow/control-flow entry) requires load-time or compile-time AspectJ weaving and cannot be implemented with proxies. This check rejects such aspects early before advisor construction.

Solutions

  1. Change the aspect instantiation model to singleton by removing the percflow value: use plain @Aspect (equivalent to @Aspect("singleton(...)")).
  2. If per-execution-flow scoping is genuinely required, switch to AspectJ compile-time (ajc) or load-time weaving instead of Spring AOP proxying.
  3. If you need per-call state, simulate it with a ThreadLocal field inside a singleton aspect.

Example fix

// before
@Aspect("percflow(execution(* com.example.Service.*(..)))")
public class FlowAspect { ... }
// after
@Aspect
public class FlowAspect {
    private final ThreadLocal<Deque<Object>> flowState = new ThreadLocal<>();
    ...
}
Defensive patterns

Strategy: validation

Validate before calling

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.AjTypeSystem;
import org.aspectj.lang.reflect.PerClauseKind;

public static boolean isSpringAopCompatible(Class<?> aspectClass) {
    var kind = AjTypeSystem.getAjType(aspectClass).getPerClause().getKind();
    return kind != PerClauseKind.PERCFLOW && kind != PerClauseKind.PERCFLOWBELOW;
}

if (!isSpringAopCompatible(MyAspect.class)) {
    throw new IllegalStateException("Aspect uses an unsupported per-clause for Spring AOP");
}

Type guard

import org.aspectj.lang.reflect.AjTypeSystem;
import org.aspectj.lang.reflect.PerClauseKind;

public static boolean isPercflow(Class<?> c) {
    return AjTypeSystem.getAjType(c).getPerClause().getKind() == PerClauseKind.PERCFLOW;
}

Try / catch

try {
    advisorFactory.validate(aspectClass);
} catch (AopConfigException ex) {
    if (ex.getMessage().contains("percflow")) {
        // rewrite the aspect or switch to AspectJ weaving
    } else throw ex;
}

Prevention

When it happens

Trigger: Annotating a class with @Aspect("percflow(pointcut)") and submitting it to Spring AOP via @EnableAspectJAutoProxy, AspectJProxyFactory.addAspect(...), or a BeanFactoryAspectJAdvisorsBuilder; calling advisorFactory.validate(aspectClass) on such a class.

Common situations: Porting an AspectJ aspect written for native AspectJ weaving into a Spring AOP application without changing the per-clause; copy-pasting an aspect from an AspectJ tutorial that uses percflow; upgrading a project where previously only AspectJ weaving was used and now @EnableAspectJAutoProxy is also active.

Related errors


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

Appendix: source

Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java:100

	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) {
		for (Class<?> annotationType : ASPECTJ_ANNOTATION_CLASSES) {
			AspectJAnnotation annotation = findAnnotation(method, (Class<Annotation>) annotationType);
			if (annotation != null) {

View on GitHub (pinned to 69bf83ad71)