spring-projects/spring-ai · error · IllegalArgumentException
The specified advisor is not part of the chain:
Error message
The specified advisor is not part of the chain:
What it means
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.
Source
Thrown at spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/DefaultAroundAdvisorChain.java:186
@Override
public CallAdvisorChain copy(CallAdvisor after) {
return this.copyAdvisorsAfter(this.getCallAdvisors(), after);
}
@Override
public StreamAdvisorChain copy(StreamAdvisor after) {
return this.copyAdvisorsAfter(this.getStreamAdvisors(), after);
}
private DefaultAroundAdvisorChain copyAdvisorsAfter(List<? extends Advisor> advisors, Advisor after) {
Assert.notNull(after, "The after advisor must not be null");
Assert.notNull(advisors, "The advisors must not be null");
int afterAdvisorIndex = advisors.indexOf(after);
if (afterAdvisorIndex < 0) {
throw new IllegalArgumentException("The specified advisor is not part of the chain: " + after.getName());
}
var remainingStreamAdvisors = advisors.subList(afterAdvisorIndex + 1, advisors.size());
return DefaultAroundAdvisorChain.builder(this.getObservationRegistry())
.observationConvention(this.observationConvention)
.pushAll(remainingStreamAdvisors)
.build();
}
@Override
public List<CallAdvisor> getCallAdvisors() {
return this.originalCallAdvisors;
}
@Override
public List<StreamAdvisor> getStreamAdvisors() {
return this.originalStreamAdvisors;View on GitHub (pinned to 98a7beda4f)
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.
Example fix
// before chain.copy(myNewToolAdvisorInstance); // not the registered one // after Advisor registered = /* the same instance passed to .advisors(...) */; chain.copy(registered);
Defensive patterns
Strategy: validation
Validate before calling
if (!chain.getAdvisors().contains(afterAdvisor)) {
throw new IllegalArgumentException("advisor not in chain: " + afterAdvisor.getName());
}
chain.copy(afterAdvisor); Try / catch
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; } Prevention
- 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().
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- At most one ToolAdvisor is allowed in the advisor chain, but
- No CallAdvisors available to execute
- mutate() must be overridden to return the most concrete Buil
- Async complete methods should use McpAsyncRequestContext ins
- Method cannot have more than one McpMeta parameter: ${method
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/dfa53a4ef608e5b8.
Report an issue: GitHub.