OpenFeign/feign · error · UnsupportedOperationException
end of MethodInterceptor chain
Error message
end of MethodInterceptor chain
What it means
This UnsupportedOperationException is thrown by MethodInterceptor.Chain.DEFAULT, a sentinel lambda that exists only to mark 'no more interceptors'. The Feign framework normally supplies a real terminal chain element that invokes the target method; if this sentinel is ever invoked, it means the interceptor chain was built without a terminal element, so there is nothing to delegate to.
Solutions
- Do not invoke the DEFAULT sentinel; ensure your interceptor only delegates when it received a real chain from Feign's invocation pipeline
- If building an interceptor chain yourself, always terminate it with the element that actually invokes the MethodHandler/target method
- Check that you are using Feign.Builder()...build() so the framework installs the real terminal chain, not a hand-rolled one
Example fix
// before
public Object intercept(MethodInvocation invocation, Chain chain) {
return chain.doInvoke(invocation); // chain may be the DEFAULT sentinel in a hand-built chain
}
// after
public Object intercept(MethodInvocation invocation, Chain chain) {
if (chain == MethodInterceptor.Chain.DEFAULT) {
throw new IllegalStateException("interceptor chain was never terminated with the real invoker");
}
return chain.doInvoke(invocation);
} Defensive patterns
Strategy: type-guard
Validate before calling
if (chain == MethodInterceptor.Chain.DEFAULT) {
throw new IllegalStateException("interceptor chain not terminated; use the chain provided by Feign's invocation pipeline");
} Type guard
boolean chainIsTerminable(MethodInterceptor.Chain chain) {
return chain != MethodInterceptor.Chain.DEFAULT;
} Prevention
- Never invoke Chain.DEFAULT directly; treat it as a marker only
- Always build clients through Feign.Builder so the framework installs the terminal invoker
- Unit-test custom interceptor chains end-to-end (proxy invocation, not just interceptor logic)
When it happens
Trigger: A MethodInterceptor implementation calls chain.doInvoke(...) (or invokes the Chain it received) when the chain it was handed is the DEFAULT sentinel — i.e., the chain was assembled or passed incorrectly, or a custom/provided chain has no real terminal invocation appended after the last interceptor.
Common situations: Writing a custom interceptor pipeline that appends interceptors but forgets to terminate with the actual method invocation; reusing a Chain object outside normal Feign.Builder invocation flow; tests or code that directly invoke Chain.DEFAULT.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Status Code [ ] has already been declared to throw [ ] and…
- Cannot generate exception - check constructor parameter…
- Too many constructors marked with @FeignExceptionConstructor
- Cannot find any suitable constructor in class
- Cannot access constructor
AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10).
Data as JSON: /api/errors/5f498ecd09a9c8a9.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/feign/interceptor/MethodInterceptor.java:86
return invocation -> intercept(invocation, chain);
}
/**
* Returns a new {@link MethodInterceptor} that invokes the current interceptor first and then the
* one passed in.
*/
default MethodInterceptor andThen(MethodInterceptor next) {
return (invocation, chain) ->
intercept(invocation, nextInvocation -> next.intercept(nextInvocation, chain));
}
/** Contract for delegation to the rest of the chain. */
interface Chain {
/** Sentinel end-of-chain that throws if invoked; the framework provides a real terminal. */
Chain DEFAULT =
invocation -> {
throw new UnsupportedOperationException("end of MethodInterceptor chain");
};
/**
* Delegate to the rest of the chain.
*
* @param invocation invocation context (typically the same instance received by {@link
* #intercept(Invocation, Chain)})
* @return value produced by the downstream chain
*/
Object next(Invocation invocation) throws Throwable;
}
}
View on GitHub (pinned to e2a1e27560)