square/retrofit · error · IllegalStateException

Response must be parameterized as Response<Foo> or Response<

Error message

Response must be parameterized as Response<Foo> or Response<? extends Foo>

What it means

Thrown by RxJava2CallAdapterFactory when the outer reactive type is parameterized but its argument is raw `Response`. The factory needs `Response<T>` to extract T; raw Response fails the check at RxJava2CallAdapterFactory.java:131. Applies to Observable, Flowable, Single, and Maybe.

Source

Thrown at retrofit-adapters/rxjava2/src/main/java/retrofit2/adapter/rxjava2/RxJava2CallAdapterFactory.java:132

    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) {
      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 RxJava2CallAdapter(
        responseType, scheduler, isAsync, isResult, isBody, isFlowable, isSingle, isMaybe, false);
  }

View on GitHub (pinned to d0b112dad0)

Solutions

  1. Parameterize Response: `Observable<Response<User>> getUser();`.
  2. Or drop the wrapper: `Observable<User> getUser();`.
  3. For unified body+error handling, use `Observable<Result<User>>`.

Example fix

// before
@GET("users/{id}")
Observable<Response> getUser(@Path("id") String id);

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

Strategy: validation

Validate before calling

for (Method m : MyService.class.getDeclaredMethods()) {
    Type rt = m.getGenericReturnType();
    if (rt instanceof ParameterizedType
            && ((ParameterizedType) rt).getActualTypeArguments()[0] == retrofit2.Response.class) {
        throw new IllegalStateException(m + " uses raw Response inside an RxJava2 type.");
    }
}

Try / catch

try {
    retrofit.create(MyService.class).getUser("1");
} catch (IllegalStateException e) {
    if (e.getMessage().contains("Response must be parameterized")) {
        throw new IllegalStateException("Fix raw Response<> inside RxJava2 return in MyService.", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: A service method returns `Observable<Response>` (or Flowable/Single/Maybe) with raw Response instead of `Observable<Response<User>>`.

Common situations: Switching a body return to a Response-wrapped return and dropping the inner generic; autocompleting Response without its argument.

Related errors


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