lysine-dev/retrofit · error · IllegalStateException
Result must be parameterized as Result<Foo> or Result<? exte
Error message
Result must be parameterized as Result<Foo> or Result<? extends Foo>
What it means
Thrown by RxJava3CallAdapterFactory when the reactive return type's argument is a raw retrofit2.adapter.rxjava3.Result. Result<T> is this adapter's wrapper that emits either the Response body or a thrown exception so subscribers receive both as stream values. The factory needs Result parameterized so it can resolve the inner body type to deserialize.
Source
Thrown at retrofit-adapters/rxjava3/src/main/java/retrofit2/adapter/rxjava3/RxJava3CallAdapterFactory.java:143
+ " 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) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException(
"Result must be parameterized" + " as Result<Foo> or Result<? extends Foo>");
}
responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
isResult = true;
} else {
responseType = observableType;
isBody = true;
}
return new RxJava3CallAdapter(
responseType, scheduler, isAsync, isResult, isBody, isFlowable, isSingle, isMaybe, false);
}
}
View on GitHub (pinned to d0b112dad0)
Solutions
- Parameterize Result with the body type: change Observable<Result> to Observable<Result<User>>.
- If you actually want the raw retrofit2.Response, use Observable<Response<User>> instead of Result.
- If you only need the body and prefer exceptions to propagate down onError, return Observable<User> directly.
- Recompile the module so the corrected signature is picked up at Retrofit.validateEagerly() time.
Example fix
// before
@GET("users/{id}")
Observable<Result> getUser(@Path("id") String id);
// after
@GET("users/{id}")
Observable<Result<User>> getUser(@Path("id") String id); Defensive patterns
Strategy: validation
Validate before calling
// The guard is method-signature discipline; there is no per-call runtime pre-check.
// Verify at test time that Result is parameterized:
Method m = ApiService.class.getMethod("getUser", String.class);
Type rt = m.getGenericReturnType();
if (rt instanceof ParameterizedType) {
Type arg = ((ParameterizedType) rt).getActualTypeArguments()[0];
if (arg == retrofit2.adapter.rxjava3.Result.class) {
throw new AssertionError("getUser() returns raw Observable<Result>; parameterize it.");
}
} Type guard
// Kotlin reified helper so Result is always parameterized at the call site.
inline fun <reified T> resultObservableType(): Type =
TypeToken<Observable<Result<T>>>() {}.type Try / catch
// Fires at Retrofit.create() time. Prefer fixing the signature; isolate like this if needed:
try {
ApiService api = retrofit.create(ApiService.class);
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().contains("Result must be parameterized")) {
throw new ConfigurationException("Service interface has a raw Observable<Result> method", e);
}
throw e;
} Prevention
- Always parameterize retrofit2.adapter.rxjava3.Result with the body type.
- Treat IDE raw-types warnings as errors for service interface files.
- Run Retrofit.create() in a unit test with eager validation to catch this before runtime.
When it happens
Trigger: A Retrofit interface method declared as Observable<Result>, Flowable<Result>, Single<Result>, or Maybe<Result> (raw Result). During Retrofit.build()/service-interface scanning the branch `rawObservableType == Result.class` runs, finds observableType is a Class not a ParameterizedType, and throws.
Common situations: Switching a stream from body-only Observable<User> to error-capturing Observable<Result> and forgetting the generic, or misreading the Result class javadoc and assuming it is self-describing without a type argument.
Related errors
- Response must be parameterized as Response<Foo> or Response<
- Future return type must be parameterized as Future<Foo> or F
- Response must be parameterized as Response<Foo> or Response<
- error == null
- response == null
AI-assisted analysis of lysine-dev/retrofit@d0b112dad0 (2026-08-13).
Data as JSON: /api/errors/5657e8d26c1484b3.
Report an issue: GitHub.