square/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
Thrown by RxJava2CallAdapterFactory while validating a service method's return type. `${name}` resolves to one of `Flowable`, `Single`, `Maybe`, or `Observable` (chosen at RxJava2CallAdapterFactory.java:117). A raw reactive type gives no body type, so no converter can be selected; the check at line 115 (`returnType instanceof ParameterizedType`) rejects it. Completable is handled separately and does not require a type parameter.
Source
Thrown at retrofit-adapters/rxjava2/src/main/java/retrofit2/adapter/rxjava2/RxJava2CallAdapterFactory.java:118
// can only be created with a single configuration.
return new RxJava2CallAdapter(
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 reactive type: `Observable<User> getUser();` (or Flowable/Single/Maybe).
- Wrap the body for HTTP metadata: `Observable<Response<User>>` or `Observable<Result<User>>`.
- Use `Completable` for no-body endpoints (no parameterization needed).
Example fix
// before
@GET("users/{id}")
Observable getUser(@Path("id") String id);
// after
@GET("users/{id}")
Observable<User> getUser(@Path("id") String id); Defensive patterns
Strategy: validation
Validate before calling
// javac -Xlint:rawtypes -Werror
for (Method m : MyService.class.getDeclaredMethods()) {
Class<?> raw = m.getReturnType();
if (raw == io.reactivex.Observable.class
|| raw == io.reactivex.Flowable.class
|| raw == io.reactivex.Single.class
|| raw == io.reactivex.Maybe.class) {
throw new IllegalStateException(m + " returns raw " + raw.getSimpleName() + "; parameterize it.");
}
} Try / catch
try {
retrofit.create(MyService.class).getUser("1");
} catch (IllegalStateException e) {
if (e.getMessage().contains("return type must be parameterized")) {
throw new IllegalStateException("Raw RxJava2 type in MyService; parameterize it.", e);
}
throw e;
} Prevention
- Treat raw-types warnings as errors.
- Only Completable needs no parameter.
- Smoke-test each service interface in CI.
When it happens
Trigger: A service method returns a raw `Observable`, `Flowable`, `Single`, or `Maybe`, e.g. `@GET("/") Observable getUser();`. name in the message reflects which raw type was detected.
Common situations: Migrating from RxJava1 to RxJava2 and dropping generics; suppressing raw-types warnings; copy-paste errors. Surfaces at first method invocation because Retrofit validates lazily.
Related errors
- ListenableFuture return type must be parameterized as Listen
- ${name} return type must be parameterized as ${name}<Foo> or
- ${name} return type must be parameterized as ${name}<Foo> or
- Response must be parameterized as Response<Foo> or Response<
- CompletableFuture return type must be parameterized as Compl
AI-assisted analysis of square/retrofit@d0b112dad0 (2026-08-04).
Data as JSON: /data/errors/a4848f3a62ed5b45.json.
Report an issue: GitHub.