{"id":"d52168ba671a7cb3","repo":"spring-projects/spring-framework","slug":"perclause-not-supported-by-spring-aop-for","errorCode":null,"errorMessage":"PerClause {} not supported by Spring AOP for {}","messagePattern":"PerClause (.+?) not supported by Spring AOP for (.+?)","errorType":"exception","errorClass":"AopConfigException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java","lineNumber":118,"sourceCode":"\t\tthis.aspectClass = ajType.getJavaClass();\n\t\tthis.ajType = ajType;\n\n\t\tswitch (this.ajType.getPerClause().getKind()) {\n\t\t\tcase SINGLETON -> {\n\t\t\t\tthis.perClausePointcut = Pointcut.TRUE;\n\t\t\t}\n\t\t\tcase PERTARGET, PERTHIS -> {\n\t\t\t\tAspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();\n\t\t\t\tajexp.setLocation(aspectClass.getName());\n\t\t\t\tajexp.setExpression(findPerClause(aspectClass));\n\t\t\t\tajexp.setPointcutDeclarationScope(aspectClass);\n\t\t\t\tthis.perClausePointcut = ajexp;\n\t\t\t}\n\t\t\tcase PERTYPEWITHIN -> {\n\t\t\t\t// Works with a type pattern\n\t\t\t\tthis.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));\n\t\t\t}\n\t\t\tdefault -> throw new AopConfigException(\n\t\t\t\t\t\"PerClause \" + ajType.getPerClause().getKind() + \" not supported by Spring AOP for \" + aspectClass);\n\t\t}\n\t}\n\n\t/**\n\t * Extract contents from String of form {@code pertarget(contents)}.\n\t */\n\tprivate String findPerClause(Class<?> aspectClass) {\n\t\tAspect ann = aspectClass.getAnnotation(Aspect.class);\n\t\tif (ann == null) {\n\t\t\treturn \"\";\n\t\t}\n\t\tString value = ann.value();\n\t\tint beginIndex = value.indexOf('(');\n\t\tif (beginIndex < 0) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn value.substring(beginIndex + 1, value.length() - 1);","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java#L100-L136","documentation":"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.","triggerScenarios":"Any aspect whose AjType per-clause resolves to PerClauseKind.PERCFLOW or PERCFLOWBELOW being processed through AspectMetadata construction (auto-proxy, AspectJProxyFactory, etc.).","commonSituations":"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.","solutions":["Remove the percflow/percflowbelow per-clause so the aspect becomes a singleton.","Switch to AspectJ compile-time or load-time weaving if control-flow scoping is required."],"exampleFix":"// before\n@Aspect(\"percflow(execution(* com.acme..*(..)))\")\npublic class CflowAspect { ... }\n// after\n@Aspect\npublic class CflowAspect { ... }","handlingStrategy":"validation","validationCode":"import org.aspectj.lang.reflect.*;\n\nvoid ensureSupportedPerClause(Class<?> c) {\n  PerClauseKind k = AjTypeSystem.getAjType(c).getPerClause().getKind();\n  if (k != PerClauseKind.SINGLETON && k != PerClauseKind.PERTARGET\n      && k != PerClauseKind.PERTHIS && k != PerClauseKind.PERTYPEWITHIN)\n    throw new IllegalStateException(\"PerClause \" + k + \" not supported for \" + c);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Whitelist per-clauses to singleton/pertarget/perthis/pertypewithin for Spring AOP.","Run a startup validation over all aspect beans."],"tags":["spring-aop","aspectj","instantiation-model","configuration"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}