spring-projects/spring-framework · error · AopConfigException

PerClause {} not supported by Spring AOP for {}

Error message

PerClause {} not supported by Spring AOP for {}

What it means

Thrown by the AspectMetadata constructor's default switch branch when the aspect's per-clause kind is none of SINGLETON, PERTARGET, PERTHIS, or PERTYPEWITHIN — i.e. PERCFLOW or PERCFLOWBELOW. This is the AspectMetadata-side guard mirroring AbstractAspectJAdvisorFactory.validate(). It rejects control-flow-based instantiation models that Spring's proxy-based AOP cannot honor.

Source

Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java:118

		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;
			}
			case PERTYPEWITHIN -> {
				// Works with a type pattern
				this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));
			}
			default -> throw new AopConfigException(
					"PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass);
		}
	}

	/**
	 * Extract contents from String of form {@code pertarget(contents)}.
	 */
	private String findPerClause(Class<?> aspectClass) {
		Aspect ann = aspectClass.getAnnotation(Aspect.class);
		if (ann == null) {
			return "";
		}
		String value = ann.value();
		int beginIndex = value.indexOf('(');
		if (beginIndex < 0) {
			return "";
		}
		return value.substring(beginIndex + 1, value.length() - 1);

View on GitHub (pinned to e8729d0438)

Solutions

  1. Remove the percflow/percflowbelow per-clause so the aspect becomes a singleton.
  2. Switch to AspectJ compile-time or load-time weaving if control-flow scoping is required.

Example fix

// before
@Aspect("percflow(execution(* com.acme..*(..)))")
public class CflowAspect { ... }
// after
@Aspect
public class CflowAspect { ... }
Defensive patterns

Strategy: validation

Validate before calling

import org.aspectj.lang.reflect.*;

void ensureSupportedPerClause(Class<?> c) {
  PerClauseKind k = AjTypeSystem.getAjType(c).getPerClause().getKind();
  if (k != PerClauseKind.SINGLETON && k != PerClauseKind.PERTARGET
      && k != PerClauseKind.PERTHIS && k != PerClauseKind.PERTYPEWITHIN)
    throw new IllegalStateException("PerClause " + k + " not supported for " + c);
}

Prevention

When it happens

Trigger: Any aspect whose AjType per-clause resolves to PerClauseKind.PERCFLOW or PERCFLOWBELOW being processed through AspectMetadata construction (auto-proxy, AspectJProxyFactory, etc.).

Common situations: Using @Aspect("percflow(...)") or @Aspect("percflowbelow(...)") in a Spring AOP context. Same root cause as errors 40/41 but hit on a different code path.

Related errors


AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04). Data as JSON: /data/errors/d52168ba671a7cb3.json. Report an issue: GitHub.