OpenFeign/feign · error · IllegalArgumentException

Method return type is not parameterized

Error message

Method return type is not parameterized: ${method}

What it means

Feign's ReflectiveFeign.verify() inspects interface methods whose return type must be a parameterized type (e.g. Response<T> for async/CompletableFuture-style methods) so it can extract the element type. This IllegalArgumentException is thrown when a method's generic return type is raw or non-parameterized, so Feign cannot determine the expected response type.

Solutions

  1. Add the type parameter to the return type, e.g. CompletableFuture<Response<MyDto>> instead of raw CompletableFuture<Response>
  2. Check the full method name in the error message and inspect that exact method in your interface
  3. If the method should not use generic returns, align it with the contract (parameterized Request/Reply types)
  4. Avoid wildcard type arguments; use concrete type parameters (see related wildcard error)

Example fix

// before
interface Api { CompletableFuture<Response> get(String id); }
// after
interface Api { CompletableFuture<Response<MyDto>> get(String id); }
Defensive patterns

Strategy: validation

Validate before calling

static void checkReturnType(java.lang.reflect.Method m) {
  if (!(m.getGenericReturnType() instanceof java.lang.reflect.ParameterizedType)) {
    throw new IllegalStateException("Return type must be parameterized: " + m);
  }
}

Type guard

if (java.lang.reflect.Method m != null && m.getGenericReturnType() instanceof java.lang.reflect.ParameterizedType pt && !(pt.getActualTypeArguments()[0] instanceof java.lang.reflect.WildcardType)) { /* safe to use */ }

Try / catch

try {
  MyApi api = Feign.builder().target(MyApi.class, url);
} catch (IllegalArgumentException e) {
  if (e.getMessage() != null && e.getMessage().contains("Method return type is not parameterized")) {
    throw new ConfigurationException("Fix interface return type: " + e.getMessage(), e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Declaring an interface method whose generic return type is not parameterized (e.g. returning a raw type or a non-generic type where a parameterized type like CompletableFuture<Response> is required) and then building a client with Feign.builder().target(...) — the check runs in verify() during proxy creation.

Common situations: Copy-pasting method signatures without generics, erasing generics to silence compiler warnings, or using a return type like CompletableFuture without the element type in async configurations.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10). Data as JSON: /api/errors/6aa1cc8ec72ac44f. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/feign/ReflectiveFeign.java:254

      }

      for (final Method m : type.getMethods()) {
        final Class<?> retType = m.getReturnType();

        if (!CompletableFuture.class.isAssignableFrom(retType)) {
          continue; // synchronous case
        }

        if (retType != CompletableFuture.class) {
          throw new IllegalArgumentException(
              "Method return type is not CompleteableFuture: "
                  + getFullMethodName(type, retType, m));
        }

        final Type genRetType = m.getGenericReturnType();

        if (!(genRetType instanceof ParameterizedType)) {
          throw new IllegalArgumentException(
              "Method return type is not parameterized: " + getFullMethodName(type, genRetType, m));
        }

        if (((ParameterizedType) genRetType).getActualTypeArguments()[0] instanceof WildcardType) {
          throw new IllegalArgumentException(
              "Wildcards are not supported for return-type parameters: "
                  + getFullMethodName(type, genRetType, m));
        }
      }
    }

    private static String getFullMethodName(Class<?> type, Type retType, Method m) {
      return retType.getTypeName() + " " + type.toGenericString() + "." + m.getName();
    }
  }
}

View on GitHub (pinned to e2a1e27560)