square/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

Thrown by the (now-deprecated) Java8CallAdapterFactory while inspecting a service method's return type. A raw `CompletableFuture` gives the factory no body type to deserialize into, so at Java8CallAdapterFactory.java:67 it rejects the raw type. Note: Retrofit now bundles CompletableFuture support, so adding this factory explicitly is unnecessary.

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

  1. Parameterize the return: `CompletableFuture<User> getUser();`.
  2. Use `CompletableFuture<Response<User>>` if you need the full HTTP Response.
  3. Since bundled support exists, remove the explicit Java8CallAdapterFactory from Retrofit.Builder unless you depend on the deprecated class -- Retrofit handles CompletableFuture natively.

Example fix

// before
@GET("users/{id}")
CompletableFuture getUser(@Path("id") String id);

// after
@GET("users/{id}")
CompletableFuture<User> getUser(@Path("id") String id);
Defensive patterns

Strategy: validation

Validate before calling

// javac -Xlint:rawtypes -Werror catches raw CompletableFuture at compile time.
// Reflection guard for completeness:
for (Method m : MyService.class.getDeclaredMethods()) {
    if (m.getGenericReturnType() == java.util.concurrent.CompletableFuture.class) {
        throw new IllegalStateException(m + " returns raw CompletableFuture.");
    }
}

Try / catch

// Fail fast during a wiring/self-test rather than at production call time:
try {
    retrofit.create(MyService.class).getUser("1");
} catch (IllegalStateException e) {
    if (e.getMessage().contains("CompletableFuture return type")) {
        throw new IllegalStateException("Raw CompletableFuture in MyService; parameterize it.", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: A service interface method returns raw `CompletableFuture` (no type argument): `@GET("/") CompletableFuture getData();`. The check `returnType instanceof ParameterizedType` at line 67 fails.

Common situations: Migrating to Java 8 futures and forgetting the generic; or explicitly adding the deprecated Java8CallAdapterFactory while writing a first method. Using a raw type to silence a compiler warning. Surfaces on first method invocation because Retrofit validates lazily.

Related errors


AI-assisted analysis of square/retrofit@d0b112dad0 (2026-08-04). Data as JSON: /data/errors/ab200ed523a7b23a.json. Report an issue: GitHub.