quarkusio/quarkus · error · RestClientDefinitionException

Using Kotlin default methods on interfaces that are not back

Error message

Using Kotlin default methods on interfaces that are not backed by Java 8 default interface methods is not supported. See https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces for more details. Offending interface is '${interface}'.

What it means

Kotlin interfaces compile default methods into a synthetic `DefaultImpls` class instead of Java 8 default interface methods unless the Kotlin compiler flag `-Xjvm-default=all` (or `all-compatibility`) is used. The REST Client runtime proxy cannot invoke these, so Quarkus detects `...DefaultImpls` in the index for an annotated Kotlin interface and throws RestClientDefinitionException.

Source

Thrown at extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/RestClientReactiveProcessor.java:964

                    defaultPriority);
        } else {
            AnnotationInstance priorityAnnoOnProvider = providerClass.declaredAnnotation(ResteasyReactiveDotNames.PRIORITY);
            if (priorityAnnoOnProvider != null) {
                priority = priorityAnnoOnProvider.value().asInt();
            }
        }
        return priority;
    }

    // By default, Kotlin does not use Java interface default methods, but generates a helper class that contains the implementation.
    // In order to avoid the extra complexity of having to deal with this mode, we simply fail the build when this situation is encountered
    // and provide an actionable error message on how to remedy the situation.
    private void validateKotlinDefaultMethods(ClassInfo jaxrsInterface, IndexView index) {
        if (jaxrsInterface.declaredAnnotation(KOTLIN_METADATA_ANNOTATION) != null) {
            var potentialDefaultImplClass = DotName
                    .createSimple(jaxrsInterface.name().toString() + KOTLIN_INTERFACE_DEFAULT_IMPL_SUFFIX);
            if (index.getClassByName(potentialDefaultImplClass) != null) {
                throw new RestClientDefinitionException(String.format(
                        "Using Kotlin default methods on interfaces that are not backed by Java 8 default interface methods is not supported. See %s for more details. Offending interface is '%s'.",
                        "https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces",
                        jaxrsInterface.name().toString()));
            }
        }
    }

    private boolean isRestMethod(MethodInfo method) {
        if (!Modifier.isAbstract(method.flags())) {
            return false;
        }
        for (AnnotationInstance annotation : method.annotations()) {
            if (annotation.target().kind() == AnnotationTarget.Kind.METHOD
                    && BUILTIN_HTTP_ANNOTATIONS_TO_METHOD.containsKey(annotation.name())) {
                return true;
            } else if (annotation.name().equals(ResteasyReactiveDotNames.PATH)) {
                return true;
            }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add `kotlinOptions.freeCompilerArgs += "-Xjvm-default=all"` to the Kotlin compile task in build.gradle(.kts) (or `<compilerArgs><arg>-Xjvm-default=all</arg></compilerArgs>` in Maven)
  2. Enable `jvmDefault = "all"` in the Kotlin toolchain
  3. Move default implementations out of the client interface into an abstract class or helper

Example fix

// before (build.gradle.kts)
tasks.withType<KotlinCompile> { kotlinOptions.jvmTarget = "17" }
// after
tasks.withType<KotlinCompile> {
    kotlinOptions.jvmTarget = "17"
    kotlinOptions.freeCompilerArgs += "-Xjvm-default=all"
}
Defensive patterns

Strategy: validation

Validate before calling

// build.gradle.kts check
val usesJvmDefaultAll = kotlin {
  compilerOptions { freeCompilerArgs.add("-Xjvm-default=all") }
}
// Quick pre-check: ensure DefaultImpls classes are absent for client interfaces
val bad = listOf("MyClient")
    .map { Class.forName(it + "$DefaultImpls") }
if (bad.isNotEmpty()) error("Enable -Xjvm-default=all; DefaultImpls found")

Prevention

When it happens

Trigger: Declaring a REST Client interface in Kotlin with default method bodies (or @JvmDefault-less compilation) and building without `-Xjvm-default=all`.

Common situations: Kotlin projects created with old Kotlin versions before jvm-default defaults; adding a default method to a client interface for convenience; shared Kotlin library compiled without the flag.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/2ce02122cd9110d2. Report an issue: GitHub.