lysine-dev/retrofit · error · IllegalStateException
${name} return type must be parameterized as ${name}<Foo> or
Error message
${name} return type must be parameterized as ${name}<Foo> or ${name}<? extends Foo> What it means
Retrofit's RxJava 3.x adapter supports Observable, Flowable, Single, and Maybe (Completable is handled separately and needs no generic). Each must carry an element type; a raw type leaves the adapter unable to resolve the emitted item type, so RxJava3CallAdapterFactory throws IllegalStateException, interpolating the actual class name ('Flowable', 'Single', 'Maybe', or 'Observable') into the message.
Source
Thrown at retrofit-adapters/rxjava3/src/main/java/retrofit2/adapter/rxjava3/RxJava3CallAdapterFactory.java:123
// can only be created with a single configuration.
return new RxJava3CallAdapter(
Void.class, scheduler, isAsync, false, true, false, false, false, true);
}
boolean isFlowable = rawType == Flowable.class;
boolean isSingle = rawType == Single.class;
boolean isMaybe = rawType == Maybe.class;
if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {
return null;
}
boolean isResult = false;
boolean isBody = false;
Type responseType;
if (!(returnType instanceof ParameterizedType)) {
String name =
isFlowable ? "Flowable" : isSingle ? "Single" : isMaybe ? "Maybe" : "Observable";
throw new IllegalStateException(
name
+ " return type must be parameterized"
+ " as "
+ name
+ "<Foo> or "
+ name
+ "<? extends Foo>");
}
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
if (rawObservableType == Response.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException(
"Response must be parameterized" + " as Response<Foo> or Response<? extends Foo>");
}
responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
} else if (rawObservableType == Result.class) {View on GitHub (pinned to d0b112dad0)
Solutions
- Parameterize the return type: `Observable<List<User>> getUsers();`, `Single<User> findUser(@Path("id") long id);`, `Maybe<User> maybeUser(@Path("id") long id);`, or `Flowable<List<User>> users();`
- For no-payload calls use Completable: `Completable deleteUser(@Path("id") long id);`
- For full response/error packaging use `Observable<Response<User>>` or `Observable<Result<User>>`.
Example fix
// before Flowable users(); // after Flowable<List<User>> users();
Defensive patterns
Strategy: validation
Validate before calling
import java.lang.reflect.*;
import io.reactivex.rxjava3.core.*;
static void assertRx3TypesParameterized(Class<?> iface) {
for (Method m : iface.getDeclaredMethods()) {
Type rt = m.getGenericReturnType();
Class<?> raw = erasure(rt);
if ((raw==Observable.class||raw==Flowable.class||raw==Single.class||raw==Maybe.class)
&& !(rt instanceof ParameterizedType)) {
throw new AssertionError("Raw " + raw.getSimpleName() + " on " + m);
}
}
} Try / catch
try {
MyService svc = retrofit.create(MyService.class);
Single<User> s = svc.findUser(id);
} catch (IllegalStateException e) {
throw new IllegalStateException("RxJava3 return type is raw on the service interface: " + e.getMessage(), e);
} Prevention
- Build with -Xlint:rawtypes so raw reactive types fail the build.
- Use Completable for no-payload methods.
- Add a reflection unit test over the service interface.
When it happens
Trigger: A method with a raw return type such as `Flowable getUsers()`, `Single findUser()`, `Maybe maybeUser()`, or `Observable users()`. Thrown in get() when `returnType` is not a ParameterizedType; `name` is chosen from isFlowable/isSingle/isMaybe, defaulting to 'Observable'.
Common situations: Migrating from `Call<T>` to RxJava 3 and omitting the generic; mixing RxJava 2 and 3 types; suppress raw-types warnings.
Related errors
- ${name} return type must be parameterized as ${name}<Foo> or
- ${name} return type must be parameterized as ${name}<Foo> or
- ListenableFuture return type must be parameterized as Listen
- Response must be parameterized as Response<Foo> or Response<
- CompletableFuture return type must be parameterized as Compl
AI-assisted analysis of lysine-dev/retrofit@d0b112dad0 (2026-08-13).
Data as JSON: /api/errors/fe7ad4a0e166559e.
Report an issue: GitHub.