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 the Scala call adapter factory when the inner type of a scala.concurrent.Future is the raw retrofit2.Response class (no type argument). After confirming the Future's inner raw type is Response (line 70), the factory requires it to be parameterized (line 75) so it can extract the body type at line 80; a raw Response is rejected with IllegalStateException.
Source
Thrown at retrofit-adapters/scala/src/main/java/retrofit2/adapter/scala/ScalaCallAdapterFactory.java:76
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Future.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalStateException(
"Future return type must be parameterized as Future<Foo> or Future<? 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);
}
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 inner Response: `Future<Response<User>> getUser()`.
- If you only need the body, use `Future<User>` directly.
- Double-check the import is retrofit2.Response and not another Response class, then add the type argument.
Example fix
// before
@GET("users/{id}")
Future<Response> getUser(@Path("id") String id);
// after
@GET("users/{id}")
Future<Response<User>> getUser(@Path("id") String id); Defensive patterns
Strategy: validation
Validate before calling
// Startup smoke test asserting the inner type of Future is never raw Response.
@Test void futureInnerResponseIsParameterized() throws Exception {
for (java.lang.reflect.Method m : MyService.class.getDeclaredMethods()) {
if (m.isDefault()) continue;
Type t = m.getGenericReturnType();
if (!(t instanceof java.lang.reflect.ParameterizedType)) continue;
Type inner = ((java.lang.reflect.ParameterizedType) t).getActualTypeArguments()[0];
assertNotEquals(retrofit2.Response.class, inner,
m.getName() + " uses raw Response inside Future; use Future<Response<BodyType>>");
}
} Try / catch
try {
MyService service = retrofit.create(MyService.class);
// exercise methods in a startup smoke test to trigger resolution
} catch (IllegalStateException e) {
throw new IllegalStateException(
"Retrofit service method return type is invalid: " + e.getMessage(), e);
} Prevention
- Always parameterize the inner Response: Future<Response<User>>.
- If you only need the body, prefer Future<User>.
- Verify the import is retrofit2.Response (not another Response class) then add the type argument.
- Resolve all service methods in a build-time test.
When it happens
Trigger: A method declared as `@GET("x") Future<Response> getUser();` (raw inner Response). The check fires at ScalaCallAdapterFactory.java:75-78 when getRawType(innerType) == Response.class but innerType is not a ParameterizedType.
Common situations: Developer wraps Future in Response to access HTTP metadata but forgets the inner type argument; Java/Scala interop dropping the generic; IDE raw import of retrofit2.Response; copy-paste from samples.
Related errors
- Future return type must be parameterized as Future<Foo> or F
- Response must be parameterized as Response<Foo> or Response<
- Result must be parameterized as Result<Foo> or Result<? exte
- ListenableFuture return type must be parameterized as Listen
- ${name} return type must be parameterized as ${name}<Foo> or
AI-assisted analysis of square/retrofit@d0b112dad0 (2026-08-04).
Data as JSON: /data/errors/956be5603339ea24.json.
Report an issue: GitHub.