{"record":{"id":"dd0fba471ad12763","repo":"spring-projects/spring-framework","slug":"advice-must-be-declared-inside-an-aspect-type-off","errorCode":null,"errorMessage":"Advice must be declared inside an aspect type: Offending method '{candidateAdviceMethod}' in class [{candidateAspectClass.getName()}]","messagePattern":"Advice must be declared inside an aspect type: Offending method '(.+?)' in class \\[(.+?)\\]","errorType":"exception","errorClass":"AopConfigException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java","lineNumber":257,"sourceCode":"\n\n\t@Override\n\tpublic @Nullable Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,\n\t\t\tMetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {\n\n\t\tClass<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();\n\t\tvalidate(candidateAspectClass);\n\n\t\tAspectJAnnotation aspectJAnnotation =\n\t\t\t\tAbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);\n\t\tif (aspectJAnnotation == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// If we get here, we know we have an AspectJ method.\n\t\t// Check that it's an AspectJ-annotated class\n\t\tif (!isAspect(candidateAspectClass)) {\n\t\t\tthrow new AopConfigException(\"Advice must be declared inside an aspect type: \" +\n\t\t\t\t\t\"Offending method '\" + candidateAdviceMethod + \"' in class [\" +\n\t\t\t\t\tcandidateAspectClass.getName() + \"]\");\n\t\t}\n\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Found AspectJ method: \" + candidateAdviceMethod);\n\t\t}\n\n\t\tAbstractAspectJAdvice springAdvice;\n\n\t\tswitch (aspectJAnnotation.getAnnotationType()) {\n\t\t\tcase AtPointcut -> {\n\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\tlogger.debug(\"Processing pointcut '\" + candidateAdviceMethod.getName() + \"'\");\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tcase AtAround -> springAdvice = new AspectJAroundAdvice(","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java#L239-L275","documentation":"Thrown as an AopConfigException from ReflectiveAspectJAdvisorFactory.getAdvice() when an advice method (carrying @Before/@After/@Around/@AfterReturning/@AfterThrowing) is discovered but isAspect(candidateAspectClass) returns false. In other words, advice annotations exist on a method of a class that is not (or is no longer considered) an aspect. This commonly happens when the aspect class is ajc-compiled and the spring.aop.ajc.ignore flag is set, or when the @Aspect annotation is not visible to the isAspect check.","triggerScenarios":"An advice method on a class without @Aspect reaching getAdvice(); an ajc-compiled aspect being processed by Spring AOP auto-proxy while spring.aop.ajc.ignore=true (isAspect returns false for ajc-compiled classes); a classloader/annotation-visibility issue making @Aspect invisible.","commonSituations":"Enabling spring.aop.ajc.ignore to avoid double-proxying but leaving advice methods on the ajc-compiled class; moving advice methods to a base class that lacks @Aspect; annotation retention or classloader issues; refactoring that removed @Aspect from a class still carrying advice annotations.","solutions":["Ensure the class declaring the advice method is annotated @Aspect (or a superclass is).","If spring.aop.ajc.ignore is set, restructure the AspectJ configuration so the ajc-compiled aspect is not also exposed to Spring AOP auto-proxying.","Verify the @Aspect annotation is on the classpath and visible to the context's classloader.","Move advice methods off non-aspect classes."],"exampleFix":"// before (and -Dspring.aop.ajc.ignore=true)\npublic class AuditHandler {\n    @Before(\"execution(* com.example.*.*(..))\")\n    public void audit() { ... }\n}\n// after\n@Aspect\npublic class AuditHandler {\n    @Before(\"execution(* com.example.*.*(..))\")\n    public void audit() { ... }\n}","handlingStrategy":"validation","validationCode":"import org.springframework.aop.aspectj.annotation.AspectJAdvisorFactory;\n\npublic static boolean isAspectAndAdviceMethods(AspectJAdvisorFactory factory, Class<?> candidateAspectClass) {\n    return factory.isAspect(candidateAspectClass);\n}\n\n// before getAdvice/getAdvisors, ensure the class is recognized as an aspect:\nif (!advisorFactory.isAspect(candidateAspectClass)) {\n    throw new IllegalStateException(candidateAspectClass + \" is not an aspect; cannot process advice methods\");\n}","typeGuard":"import org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory;\n\npublic static boolean isRecognizedAspect(Class<?> c) {\n    return new ReflectiveAspectJAdvisorFactory().isAspect(c);\n}","tryCatchPattern":"try {\n    Advice advice = advisorFactory.getAdvice(method, pointcut, factory, order, name);\n} catch (AopConfigException ex) {\n    if (ex.getMessage().startsWith(\"Advice must be declared inside an aspect type\")) {\n        // ensure @Aspect is present, or unset spring.aop.ajc.ignore\n    } else throw ex;\n}","preventionTips":["Keep @Aspect on every class that declares advice methods.","If enabling spring.aop.ajc.ignore=true, ensure ajc-compiled aspects are not also auto-proxied by Spring.","Add a startup assertion that advisorFactory.isAspect(type) holds for all advice-bearing beans."],"tags":["spring-aop","aspectj","configuration","annotations","ajc"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}