{"record":{"id":"dfa53a4ef608e5b8","repo":"spring-projects/spring-ai","slug":"the-specified-advisor-is-not-part-of-the-chain","errorCode":null,"errorMessage":"The specified advisor is not part of the chain: ","messagePattern":"The specified advisor is not part of the chain: ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/DefaultAroundAdvisorChain.java","lineNumber":186,"sourceCode":"\t@Override\n\tpublic CallAdvisorChain copy(CallAdvisor after) {\n\t\treturn this.copyAdvisorsAfter(this.getCallAdvisors(), after);\n\t}\n\n\t@Override\n\tpublic StreamAdvisorChain copy(StreamAdvisor after) {\n\t\treturn this.copyAdvisorsAfter(this.getStreamAdvisors(), after);\n\t}\n\n\tprivate DefaultAroundAdvisorChain copyAdvisorsAfter(List<? extends Advisor> advisors, Advisor after) {\n\n\t\tAssert.notNull(after, \"The after advisor must not be null\");\n\t\tAssert.notNull(advisors, \"The advisors must not be null\");\n\n\t\tint afterAdvisorIndex = advisors.indexOf(after);\n\n\t\tif (afterAdvisorIndex < 0) {\n\t\t\tthrow new IllegalArgumentException(\"The specified advisor is not part of the chain: \" + after.getName());\n\t\t}\n\n\t\tvar remainingStreamAdvisors = advisors.subList(afterAdvisorIndex + 1, advisors.size());\n\n\t\treturn DefaultAroundAdvisorChain.builder(this.getObservationRegistry())\n\t\t\t.observationConvention(this.observationConvention)\n\t\t\t.pushAll(remainingStreamAdvisors)\n\t\t\t.build();\n\t}\n\n\t@Override\n\tpublic List<CallAdvisor> getCallAdvisors() {\n\t\treturn this.originalCallAdvisors;\n\t}\n\n\t@Override\n\tpublic List<StreamAdvisor> getStreamAdvisors() {\n\t\treturn this.originalStreamAdvisors;","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/DefaultAroundAdvisorChain.java#L168-L204","documentation":"copyAdvisorsAfter(advisor, advisors) splits an advisor list at a given 'after' advisor to build a new chain; if the advisor isn't in the list, indexOf returns -1 and an IllegalArgumentException is thrown naming the missing advisor. It's triggered from copy() when copying a chain using an advisor that isn't part of it.","triggerScenarios":"Calling copy() on an advisor chain passing an 'after' advisor instance that is not contained in the chain — typically a different instance than the one registered (equal contents but distinct object), or an advisor that was never added.","commonSituations":"Rebuilding a chain from a cached/ad-hoc advisor instance instead of the one originally registered; advisor registered by class but copy called with a freshly constructed instance without proper equals/hashCode; typo in advisor wiring.","solutions":["Use the exact advisor instance (or a correctly equal one) that was added to the chain when calling copy().","Verify with advisors.contains(advisor) before copying.","Add the advisor to the chain first if it's supposed to be part of it.","Prefer copying by index or rebuilding the chain explicitly if identity matching is the issue."],"exampleFix":"// before\nchain.copy(myNewToolAdvisorInstance); // not the registered one\n// after\nAdvisor registered = /* the same instance passed to .advisors(...) */;\nchain.copy(registered);","handlingStrategy":"validation","validationCode":"if (!chain.getAdvisors().contains(afterAdvisor)) {\n  throw new IllegalArgumentException(\"advisor not in chain: \" + afterAdvisor.getName());\n}\nchain.copy(afterAdvisor);","typeGuard":null,"tryCatchPattern":"try { chain.copy(after); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith(\"The specified advisor is not part of the chain\")) { /* use the registered instance */ } throw e; }","preventionTips":["Keep references to the exact advisor instances you registered.","Ensure custom advisors implement equals/hashCode consistently if passing equivalent instances.","Verify membership with contains() before copy()."],"tags":["advisor-chain","argument-error","spring-ai"],"backgroundTag":"invalid-argument-value","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}