{"id":"3149830ab074eb2d","repo":"spring-projects/spring-framework","slug":"unknown-advisor-type-next-getclass-can-only-i","errorCode":null,"errorMessage":"Unknown advisor type {next.getClass()}; can only include Advisor or Advice type beans in interceptorNames chain except for last entry which may also be target instance or TargetSource","messagePattern":"Unknown advisor type (.+?); can only include Advisor or Advice type beans in interceptorNames chain except for last entry which may also be target instance or TargetSource","errorType":"exception","errorClass":"AopConfigException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java","lineNumber":558,"sourceCode":"\t\t\t\tlogger.debug(\"Refreshing target with name '\" + this.targetName + \"'\");\n\t\t\t}\n\t\t\tObject target = this.beanFactory.getBean(this.targetName);\n\t\t\treturn (target instanceof TargetSource targetSource ? targetSource : new SingletonTargetSource(target));\n\t\t}\n\t}\n\n\t/**\n\t * Convert the following object sourced from calling getBean() on a name in the\n\t * interceptorNames array to an Advisor or TargetSource.\n\t */\n\tprivate Advisor namedBeanToAdvisor(Object next) {\n\t\ttry {\n\t\t\treturn this.advisorAdapterRegistry.wrap(next);\n\t\t}\n\t\tcatch (UnknownAdviceTypeException ex) {\n\t\t\t// We expected this to be an Advisor or Advice,\n\t\t\t// but it wasn't. This is a configuration error.\n\t\t\tthrow new AopConfigException(\"Unknown advisor type \" + next.getClass() +\n\t\t\t\t\t\"; can only include Advisor or Advice type beans in interceptorNames chain \" +\n\t\t\t\t\t\"except for last entry which may also be target instance or TargetSource\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Blow away and recache singleton on an advice change.\n\t */\n\t@Override\n\tprotected void adviceChanged() {\n\t\tsuper.adviceChanged();\n\t\tif (this.singleton) {\n\t\t\tlogger.debug(\"Advice has changed; re-caching singleton instance\");\n\t\t\tsynchronized (this) {\n\t\t\t\tthis.singletonInstance = null;\n\t\t\t}\n\t\t}\n\t}","sourceCodeStart":540,"sourceCodeEnd":576,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java#L540-L576","documentation":"namedBeanToAdvisor() delegates to advisorAdapterRegistry.wrap(); if that throws UnknownAdviceTypeException (the bean is neither MethodInterceptor, nor a supported Advice like MethodBeforeAdvice/AfterReturningAdvice/ThrowsAdvice, nor an Advisor), ProxyFactoryBean wraps it as AopConfigException. The rule is: every interceptorNames entry must be an Advisor or Advice, except the LAST entry which may also be the target instance or a TargetSource.","triggerScenarios":"Listing a bean in interceptorNames (other than the final slot) whose type is a plain POJO with no AOP advice interface; accidentally putting the target in the middle of the chain; referencing an advice whose adapter was not registered.","commonSituations":"Misordering interceptorNames so the target is not last; bean type changed (refactor) so it no longer implements an advice interface; using a custom Advice type without registering a matching AdvisorAdapter.","solutions":["Verify each non-final interceptorNames entry implements Advisor, MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice, or ThrowsAdvice.","Ensure the target bean is the LAST entry in interceptorNames (or use target/targetName instead).","Register a custom AdvisorAdapter via AdvisorAdapterRegistry if using a non-standard Advice type."],"exampleFix":"// before\n<property name=\"interceptorNames\" value=\"myTarget,myAdvice\"/> <!-- target not last -->\n\n// after\n<property name=\"interceptorNames\" value=\"myAdvice\"/>\n<property name=\"targetName\" value=\"myTarget\"/>","handlingStrategy":"type-guard","validationCode":"// Validate each named entry's type before adding to the chain\nfor (int i = 0; i < names.length; i++) {\n    Class<?> type = beanFactory.getType(names[i]);\n    boolean last = (i == names.length - 1);\n    boolean ok = type != null &&\n        (org.springframework.aop.Advisor.class.isAssignableFrom(type)\n            || org.aopalliance.aop.Advice.class.isAssignableFrom(type)\n            || (last && (org.springframework.aop.TargetSource.class.isAssignableFrom(type) || true)));\n    if (!ok) throw new IllegalArgumentException(\"Entry '\" + names[i] + \"' is not Advisor/Advice\" + (last ? \" (or target)\" : \"\"));\n}","typeGuard":"public static boolean isAdviceOrAdvisor(Class<?> c) {\n    return c != null && (org.springframework.aop.Advisor.class.isAssignableFrom(c)\n        || org.aopalliance.aop.Advice.class.isAssignableFrom(c));\n}","tryCatchPattern":"try {\n    pfb.setInterceptorNames(names);\n    return pfb.getObject();\n} catch (AopConfigException ex) {\n    if (ex.getMessage().contains(\"Unknown advisor type\")) {\n        throw new ConfigurationException(\"interceptorNames contains a non-advice bean; check ordering\", ex);\n    }\n    throw ex;\n}","preventionTips":["Keep the target as the LAST entry of interceptorNames, or use target/targetName.","Use beanFactory.getType(name) to pre-check each non-final entry implements Advice/Advisor.","Register custom AdvisorAdapters for non-standard advice types."],"tags":["aop","proxy-factory-bean","advice","advisor","configuration"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}