OpenFeign/feign · error · IllegalArgumentException
Method can't have continuation argument, only kotlin method…
Error message
Method %s can't have continuation argument, only kotlin method is allowed
What it means
KotlinMethodInfo.createInstance() validates that a method detected as a Kotlin suspend function actually has a resolvable Kotlin return type. If MethodKt.isSuspend(method) is true but getKotlinMethodReturnType returns null, it throws IllegalArgumentException stating the method can't have a continuation argument unless it is a proper Kotlin method.
Solutions
- Ensure the interface is authored in Kotlin and compiled with the same/m compatible Kotlin version as feign-kotlin
- Remove the Continuation parameter from Java-declared methods; declare them as suspend fun in Kotlin instead
- Verify the jar containing the interface was not obfuscated/processed in a way that strips @Metadata annotations
- Check the generated configKey in the message to identify the offending method and fix its declaration
Example fix
// before (Java interface)
Response getData(Continuation<? super Response> cont);
// after (Kotlin interface)
interface Api { suspend fun getData(): Response } Defensive patterns
Strategy: validation
Validate before calling
// before building the target
Method m = Api.class.getMethod("getData");
if (MethodKt.isSuspend(m) && MethodKt.getKotlinMethodReturnType(m) == null) {
throw new IllegalStateException("Method " + m + " must be declared as suspend fun in Kotlin");
} Try / catch
try { Feign.builder().target(Api.class, url); }
catch (IllegalArgumentException e) {
if (e.getMessage().contains("continuation argument")) throw new IllegalStateException("Declare the method as suspend fun in Kotlin", e);
throw e;
} Prevention
- Define Feign interfaces in Kotlin when using feign-kotlin suspend support
- Keep Kotlin stdlib/plugin versions consistent across modules
- Avoid bytecode post-processing/obfuscation of Feign interface jars
When it happens
Trigger: Registering a Feign target interface whose method is a suspend function compiled without Kotlin metadata, or a method whose last parameter is a Continuation but which is not a genuine suspend function (e.g. hand-written or processed by bytecode tools that strip metadata).
Common situations: Mixing Kotlin and Java modules where the interface was recompiled/obfuscated; using the feign-kotlin module with an interface written in Java that takes a kotlin.coroutines.Continuation parameter; Kotlin version mismatches altering metadata the reflection helpers rely on.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Not supported type
- Not an iterator type
- Status Code [ ] has already been declared to throw [ ] and…
- Cannot generate exception - check constructor parameter…
- Too many constructors marked with @FeignExceptionConstructor
AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10).
Data as JSON: /api/errors/0469751f76e4fa89.
Report an issue: GitHub.
Appendix: source
Thrown at kotlin/src/main/java/feign/kotlin/KotlinMethodInfo.java:42
import java.util.concurrent.CompletableFuture;
class KotlinMethodInfo extends MethodInfo {
KotlinMethodInfo(Type underlyingReturnType, boolean asyncReturnType) {
super(underlyingReturnType, asyncReturnType);
}
static KotlinMethodInfo createInstance(Class<?> targetType, Method method) {
final Type type = Types.resolve(targetType, targetType, method.getGenericReturnType());
Type underlyingReturnType;
boolean asyncReturnType;
if (MethodKt.isSuspend(method)) {
asyncReturnType = true;
underlyingReturnType = MethodKt.getKotlinMethodReturnType(method);
if (underlyingReturnType == null) {
String configKey = Feign.configKey(targetType, method);
throw new IllegalArgumentException(
String.format(
"Method %s can't have continuation argument, only kotlin method is allowed",
configKey));
}
} else if (type instanceof ParameterizedType
&& Types.getRawType(type).isAssignableFrom(CompletableFuture.class)) {
asyncReturnType = true;
underlyingReturnType = ((ParameterizedType) type).getActualTypeArguments()[0];
} else {
asyncReturnType = false;
underlyingReturnType = type;
}
return new KotlinMethodInfo(underlyingReturnType, asyncReturnType);
}
}
View on GitHub (pinned to e2a1e27560)