{"id":"a5876cd250f1c2d0","repo":"square/retrofit","slug":"response-must-be-parameterized-as-response-foo-or","errorCode":null,"errorMessage":"Response must be parameterized as Response<Foo> or Response<? extends Foo>","messagePattern":"Response must be parameterized as Response<Foo> or Response<\\? extends Foo>","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"retrofit-adapters/guava/src/main/java/retrofit2/adapter/guava/GuavaCallAdapterFactory.java","lineNumber":81,"sourceCode":"      Type returnType, Annotation[] annotations, Retrofit retrofit) {\n    if (getRawType(returnType) != ListenableFuture.class) {\n      return null;\n    }\n    if (!(returnType instanceof ParameterizedType)) {\n      throw new IllegalStateException(\n          \"ListenableFuture return type must be parameterized\"\n              + \" as ListenableFuture<Foo> or ListenableFuture<? extends Foo>\");\n    }\n    Type innerType = getParameterUpperBound(0, (ParameterizedType) returnType);\n\n    if (getRawType(innerType) != Response.class) {\n      // Generic type is not Response<T>. Use it for body-only adapter.\n      return new BodyCallAdapter<>(innerType);\n    }\n\n    // Generic type is Response<T>. Extract T and create the Response version of the adapter.\n    if (!(innerType instanceof ParameterizedType)) {\n      throw new IllegalStateException(\n          \"Response must be parameterized\" + \" as Response<Foo> or Response<? extends Foo>\");\n    }\n    Type responseType = getParameterUpperBound(0, (ParameterizedType) innerType);\n    return new ResponseCallAdapter<>(responseType);\n  }\n\n  private static final class BodyCallAdapter<R> implements CallAdapter<R, ListenableFuture<R>> {\n    private final Type responseType;\n\n    BodyCallAdapter(Type responseType) {\n      this.responseType = responseType;\n    }\n\n    @Override\n    public Type responseType() {\n      return responseType;\n    }\n","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/square/retrofit/blob/d0b112dad073b7fe49c953ebc46ff1b424cb1e51/retrofit-adapters/guava/src/main/java/retrofit2/adapter/guava/GuavaCallAdapterFactory.java#L63-L99","documentation":"Thrown by GuavaCallAdapterFactory when the future IS parameterized, but its single type argument is the raw `Response` class (e.g. `ListenableFuture<Response>`). The factory detected Response as the inner type and then needs to extract the body type T from `Response<T>`; a raw Response leaves T unknown, so at GuavaCallAdapterFactory.java:80 it throws.","triggerScenarios":"A service method returns `ListenableFuture<Response>` (raw Response) rather than `ListenableFuture<Response<Foo>>`. The check `innerType instanceof ParameterizedType` at line 80 fails because Response has no type arguments.","commonSituations":"Wrapping a return in Response to get status/headers but forgetting to also parameterize Response with the body type; refactoring a body return into a Response return and losing the inner generic; or autocompleting `Response` without its argument.","solutions":["Parameterize the inner Response with the body type: `ListenableFuture<Response<User>> getUser();`.","If you do not actually need the Response wrapper, drop it and return `ListenableFuture<User>` directly.","Rebuild; the factory will resolve responseType and return a ResponseCallAdapter."],"exampleFix":"// before\n@GET(\"users/{id}\")\nListenableFuture<Response> getUser(@Path(\"id\") String id);\n\n// after\n@GET(\"users/{id}\")\nListenableFuture<Response<User>> getUser(@Path(\"id\") String id);","handlingStrategy":"validation","validationCode":"// Scan service methods for a raw Response nested inside a future type.\nfor (Method m : MyService.class.getDeclaredMethods()) {\n    Type rt = m.getGenericReturnType();\n    if (rt instanceof ParameterizedType\n            && ((ParameterizedType) rt).getRawType() == retrofit2.Response.class) {\n        throw new IllegalStateException(m + \" uses raw Response; parameterize Response<T>.\");\n    }\n    // also handle Response nested one level deep, e.g. ListenableFuture<Response>\n}","typeGuard":null,"tryCatchPattern":"// Programming error -- do not silently swallow. Fail fast in a wiring test:\ntry {\n    retrofit.create(MyService.class).getUser(\"1\");\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"Response must be parameterized\")) {\n        throw new IllegalStateException(\"Fix raw Response<> in MyService.\", e);\n    }\n    throw e;\n}","preventionTips":["When introducing Response<>, always carry the body type into it.","Let the IDE's raw-types inspection flag this before runtime.","Keep a unit test that exercises each service method to surface adapter errors at build time."],"tags":["retrofit","guava","java","reflection","type-erasure","response-wrapper"],"analyzedSha":"d0b112dad073b7fe49c953ebc46ff1b424cb1e51","analyzedAt":"2026-08-04T19:12:59.096Z","schemaVersion":2}