OpenFeign/feign · error · IllegalStateException
Expected only one contained type.
Error message
Expected only one contained type.
What it means
After confirming the method returns a Publisher, the contract reads the Publisher's actual type arguments to rewrite the method's return type to the contained type. If the Publisher declares more than one type parameter, the contained type is ambiguous, so an IllegalStateException is thrown. Standard reactive types only have one type parameter, so this is an internal invariant check.
Solutions
- Use standard Publisher types (Flux<T>, Mono<T>, Observable<T>) which have exactly one type parameter
- Remove extra type parameters from any custom Publisher subtype used as a return type
- If you need multiple values, wrap them in a single POJO and return Publisher<YourPojo>
Example fix
// before
class WeirdPublisher<T, U> implements Publisher<T> {}
WeirdPublisher<String, Long> get();
// after
Flux<String> get(); // one type parameter only
Defensive patterns
Strategy: type-guard
Validate before calling
if (Publisher.class.isAssignableFrom(raw) && ((ParameterizedType) type).getActualTypeArguments().length != 1)
throw new IllegalStateException("Publisher return types must have exactly one type parameter"); Type guard
static boolean hasSingleTypeParameter(Type t) {
return t instanceof ParameterizedType
&& ((ParameterizedType) t).getActualTypeArguments().length == 1;
} Prevention
- Stick to Flux/Mono/Observable as return types; avoid custom Publisher subtypes with extra generics
When it happens
Trigger: Declaring a return type parameterized with more than one type argument that (transitively) implements Publisher, e.g. a custom interface extending Publisher with an extra type parameter, which passes isReactive() but yields actualTypes.length > 1.
Common situations: Custom reactive wrapper classes or interfaces with extra generics; third-party reactive types parameterized unconventionally; raw misuse of ParameterizedType contracts.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Method of contract doesn't returns a…
- Method return type is not parameterized
- Wildcards are not supported for return-type parameters
- Not supported type
- Not an iterator type
AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10).
Data as JSON: /api/errors/0c9eeed697671b4d.
Report an issue: GitHub.
Appendix: source
Thrown at reactive/src/main/java/feign/reactive/ReactiveDelegatingContract.java:54
public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
List<MethodMetadata> methodsMetadata = this.delegate.parseAndValidateMetadata(targetType);
for (final MethodMetadata metadata : methodsMetadata) {
final Type type = metadata.returnType();
if (!isReactive(type)) {
throw new IllegalArgumentException(
String.format(
"Method %s of contract %s doesn't returns a org.reactivestreams.Publisher",
metadata.configKey(), targetType.getSimpleName()));
}
/*
* we will need to change the return type of the method to match the return type contained
* within the Publisher
*/
Type[] actualTypes = ((ParameterizedType) type).getActualTypeArguments();
if (actualTypes.length > 1) {
throw new IllegalStateException("Expected only one contained type.");
} else {
Class<?> actual = Types.getRawType(actualTypes[0]);
if (Stream.class.isAssignableFrom(actual)) {
throw new IllegalArgumentException(
"Streams are not supported when using Reactive Wrappers");
}
metadata.returnType(type);
}
}
return methodsMetadata;
}
/**
* Ensure that the type provided implements a Reactive Streams Publisher.
*
* @param type to inspect.
* @return true if the type implements the Reactive Streams Publisher specification.View on GitHub (pinned to e2a1e27560)