# Kotlin's JDK release compatibility flag

DevFeed: [Kotlin's JDK release compatibility flag](<https://devfeed.tech/articles/kotlin-s-jdk-release-compatibility-flag-20945.md>)

Original publisher: [Read original article](<https://jakewharton.com/kotlins-jdk-release-compatibility-flag/>)

Published: 2024-03-13T00:00:00Z

Content type: tutorial

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Java](<https://devfeed.tech/topics/java.md>), [Android](<https://devfeed.tech/topics/android.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [app](<https://devfeed.tech/tags/app.md>), [code](<https://devfeed.tech/tags/code.md>), [compatibility](<https://devfeed.tech/tags/compatibility.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [exception](<https://devfeed.tech/tags/exception.md>), [ide](<https://devfeed.tech/tags/ide.md>), [java](<https://devfeed.tech/tags/java.md>), [jdk](<https://devfeed.tech/tags/jdk.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>)

## AI overview

This article explains how compiling Kotlin code with JDK 21 can expose newer JDK APIs even when the Kotlin JVM bytecode target is set to Java 8. That caused a Kotlin extension call to resolve to the newer List member method, producing NoSuchMethodError on Android. It presents Kotlin's jvm-target validation flag, which restricts compilation against APIs unavailable in the intended target JDK.

## Source excerpt

Yesterday, our Android app crashed with a weird NoSuchMethodError. java.lang.NoSuchMethodError: No interface method removeFirst()Ljava/lang/Object; in class Ljava/util/List; or its super classes (declaration of 'java.util.List' appears in /apex/com.android.art/javalib/core-oj.jar) at app.cash.redwood.lazylayout.widget.LazyListUpdateProcessor.onEndChanges(SourceFile:165) at app.cash.redwood.lazylayout.view.ViewLazyList.onEndChanges(SourceFile:210) at app.cash.redwood.protocol.widget.ProtocolBridge.sendChanges(SourceFile:125) at app.cash.redwood.treehouse.ViewContentCodeBinding.receiveChangesOnUiDispatcher(SourceFile:419) at app.cash.redwood.treehouse.ViewContentCodeBinding$sendChanges$1.invokeSuspend(SourceFile:383) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(SourceFile:33) at kotlinx.coroutines.DispatchedTask.run(SourceFile:104) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:250) at android.app.ActivityThread.main(ActivityThread.java:7868) The offending code is written in Kotlin, and looks like this: The IDE showing an italicized blue style for removeFirst means it's a Kotlin extension function which compiles down to a static helper in the bytecode. However, the exception clearly indicates we are calling a member function on List directly. What gives? In JDK 21, as part of the sequenced collection effort, the List interface added removeFirst() and removeLast() methods. According to the Kotlin docs on extension functions: If a class has a member function, and an extension function is defined which has the same receiver type, the same name, and is applicable to given arguments, the member always wins. When we bumped our build JDK to 21, the new member became available and accidentally took precedence. Oops! But wait, we set our Kotlin jvmTarget to 1.8 in order to be backwards compatible. Is that not enough? val javaVersion = JavaVersion.VERSION_1_