{"id":"3374365aab92c13e","repo":"spring-projects/spring-framework","slug":"aspect-class-does-not-define-a-singleton-aspe","errorCode":null,"errorMessage":"Aspect class [{}] does not define a singleton aspect","messagePattern":"Aspect class \\[(.+?)\\] does not define a singleton aspect","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectJProxyFactory.java","lineNumber":96,"sourceCode":"\t */\n\tpublic AspectJProxyFactory(Class<?>... interfaces) {\n\t\tsetInterfaces(interfaces);\n\t}\n\n\n\t/**\n\t * Add the supplied aspect instance to the chain. The type of the aspect instance\n\t * supplied must be a singleton aspect. True singleton lifecycle is not honored when\n\t * using this method - the caller is responsible for managing the lifecycle of any\n\t * aspects added in this way.\n\t * @param aspectInstance the AspectJ aspect instance\n\t */\n\tpublic void addAspect(Object aspectInstance) {\n\t\tClass<?> aspectClass = aspectInstance.getClass();\n\t\tString aspectName = aspectClass.getName();\n\t\tAspectMetadata am = createAspectMetadata(aspectClass, aspectName);\n\t\tif (am.getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Aspect class [\" + aspectClass.getName() + \"] does not define a singleton aspect\");\n\t\t}\n\t\taddAdvisorsFromAspectInstanceFactory(\n\t\t\t\tnew SingletonMetadataAwareAspectInstanceFactory(aspectInstance, aspectName));\n\t}\n\n\t/**\n\t * Add an aspect of the supplied type to the end of the advice chain.\n\t * @param aspectClass the AspectJ aspect class\n\t */\n\tpublic void addAspect(Class<?> aspectClass) {\n\t\tString aspectName = aspectClass.getName();\n\t\tAspectMetadata am = createAspectMetadata(aspectClass, aspectName);\n\t\tMetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectClass, aspectName);\n\t\taddAdvisorsFromAspectInstanceFactory(instanceFactory);\n\t}\n\n","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectJProxyFactory.java#L78-L114","documentation":"Thrown by AspectJProxyFactory.addAspect(Object aspectInstance) when the supplied aspect instance's class does not declare a singleton per-clause (i.e. it is pertarget/perthis/pertypewithin/percflow/percflowbelow). addAspect(Object) requires a concrete singleton instance because the caller manages its lifecycle; non-singleton aspects must be added by class via addAspect(Class).","triggerScenarios":"Calling new AspectJProxyFactory(target).addAspect(myAspectInstance) where myAspectInstance.getClass() is annotated @Aspect(\"pertarget(...)\") or similar non-singleton per-clause.","commonSituations":"Passing a pre-built instance of a per-object aspect to AspectJProxyFactory. Confusing the two addAspect overloads — addAspect(Object) is singleton-only, addAspect(Class) supports non-singleton instantiation models.","solutions":["Switch to addAspect(MyAspect.class) so Spring creates per-target instances via a PrototypeAspectInstanceFactory.","Change the aspect to singleton (remove the per-clause) if you want to keep passing an instance.","Ensure the instance you pass is of a class annotated as a plain @Aspect (singleton)."],"exampleFix":"// before\nfactory.addAspect(new PerTargetAspect()); // @Aspect(\"pertarget(...)\")\n// after\nfactory.addAspect(PerTargetAspect.class);","handlingStrategy":"validation","validationCode":"import org.aspectj.lang.reflect.*;\n\nboolean isSingletonAspect(Class<?> c) {\n  return AjTypeSystem.getAjType(c).getPerClause().getKind() == PerClauseKind.SINGLETON;\n}\n\n// before calling addAspect(instance):\nif (!isSingletonAspect(instance.getClass())) {\n  // use addAspect(Class) instead\n  factory.addAspect(instance.getClass());\n} else {\n  factory.addAspect(instance);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use addAspect(Class) for non-singleton aspects; reserve addAspect(Object) for singleton instances.","Annotate per-clause aspects consistently and document which addAspect overload to use."],"tags":["spring-aop","aspectj","instantiation-model","aspectj-proxy-factory"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}