lysine-dev/retrofit · error · IllegalStateException
CompletableFuture return type must be parameterized as Compl
Error message
CompletableFuture return type must be parameterized as CompletableFuture<Foo> or CompletableFuture<? extends Foo>
What it means
Retrofit's Java 8 adapter handles methods returning java.util.concurrent.CompletableFuture, but only when the return type is parameterized with an element type. A raw CompletableFuture has no type information, so Java8CallAdapterFactory cannot determine the body type to deserialize and throws IllegalStateException during call-adapter resolution.
Source
Thrown at retrofit-adapters/java8/src/main/java/retrofit2/adapter/java8/Java8CallAdapterFactory.java:67
* errors
* </ul>
*/
@Deprecated
public final class Java8CallAdapterFactory extends CallAdapter.Factory {
public static Java8CallAdapterFactory create() {
return new Java8CallAdapterFactory();
}
private Java8CallAdapterFactory() {}
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != CompletableFuture.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalStateException(
"CompletableFuture return type must be parameterized"
+ " as CompletableFuture<Foo> or CompletableFuture<? extends Foo>");
}
Type innerType = getParameterUpperBound(0, (ParameterizedType) returnType);
if (getRawType(innerType) != Response.class) {
// Generic type is not Response<T>. Use it for body-only adapter.
return new BodyCallAdapter<>(innerType);
}
// Generic type is Response<T>. Extract T and create the Response version of the adapter.
if (!(innerType instanceof ParameterizedType)) {
throw new IllegalStateException(
"Response must be parameterized" + " as Response<Foo> or Response<? extends Foo>");
}
Type responseType = getParameterUpperBound(0, (ParameterizedType) innerType);
return new ResponseCallAdapter<>(responseType);
}View on GitHub (pinned to d0b112dad0)
Solutions
- Parameterize the return type with the body type: `CompletableFuture<User> getUser(@Path("id") long id);`
- For full HTTP responses: `CompletableFuture<Response<User>> getUser(@Path("id") long id);`
- Remove raw-types suppressions and resolve every compiler warning.
Example fix
// before
CompletableFuture getUser(@Path("id") long id);
// after
CompletableFuture<User> getUser(@Path("id") long id); Defensive patterns
Strategy: validation
Validate before calling
import java.lang.reflect.*;
static void assertFuturesParameterized(Class<?> iface) {
for (Method m : iface.getDeclaredMethods()) {
Type rt = m.getGenericReturnType();
if (rt.getTypeName().startsWith("java.util.concurrent.CompletableFuture")
&& !(rt instanceof ParameterizedType)) {
throw new AssertionError("Raw CompletableFuture return type on " + m);
}
}
} Try / catch
try {
MyService svc = retrofit.create(MyService.class);
CompletableFuture<User> f = svc.getUser(id);
} catch (IllegalStateException e) {
throw new IllegalStateException("Service interface has a raw CompletableFuture return type: " + e.getMessage(), e);
} Prevention
- Build with -Xlint:rawtypes to fail on raw types.
- Add a unit test calling assertFuturesParameterized(MyService.class).
- Do not suppress raw-types warnings on service interfaces.
When it happens
Trigger: Declaring a method with a raw return type such as `CompletableFuture getUser();`. Thrown on first invocation of that method via the Retrofit proxy, inside Java8CallAdapterFactory.get() when `returnType` is not a ParameterizedType.
Common situations: Switching from `Call<T>` to CompletableFuture and omitting the generic; IDE inserting the raw type; using the java8 adapter on a project that previously returned `Call`.
Related errors
- Response must be parameterized as Response<Foo> or Response<
- ListenableFuture return type must be parameterized as Listen
- Response must be parameterized as Response<Foo> or Response<
- ${name} return type must be parameterized as ${name}<Foo> or
- Response must be parameterized as Response<Foo> or Response<
AI-assisted analysis of lysine-dev/retrofit@d0b112dad0 (2026-08-13).
Data as JSON: /api/errors/b5b8911d7e58e02a.
Report an issue: GitHub.