General info
- okio / okio-fakefilesystem: 3.17.0
- Kotlin: 2.4.0 (Kotlin/Wasm)
- kotlinx-datetime in the app: 0.8.0 (regular artifact)
- Target: wasmJs only (JVM/Android/iOS link fine)
What happens
okio-fakefilesystem:3.17.0 declares a dependency on org.jetbrains.kotlinx:kotlinx-datetime:0.7.1-0.6.x-compat, i.e. the artifact that keeps kotlinx.datetime.Clock / kotlinx.datetime.Instant as concrete classes. The published okio-fakefilesystem-wasm-js klib was therefore compiled with references to signature kotlinx.datetime/Clock (and …/Instant) as classes — via the deprecated FakeFileSystem(kotlinx.datetime.Clock) constructor and the kotlinx.datetime.Instant fields on FileMetadata.
An application that uses the regular kotlinx-datetime:0.8.0 gets kotlinx.datetime.Clock as a typealias to kotlin.time.Clock at the same signature. Gradle resolves a single datetime version (0.8.0), so there are not "two versions" on the classpath — but the wasmJs IR linker still binds signature kotlinx.datetime/Clock twice (once as the class reference deserialized from okio-fakefilesystem, once as the typealias from kotlinx-datetime:0.8.0) and fails:
e: java.lang.IllegalStateException: IrTypeAliasSymbolImpl is already bound.
Signature: kotlinx.datetime/Clock|null[0].
Owner: TYPEALIAS name:Clock visibility:public expandedType:kotlin.time.Clock
at org.jetbrains.kotlin.ir.symbols.impl.IrSymbolBase.bind(IrSymbolImpl.kt:68)
at org.jetbrains.kotlin.ir.declarations.impl.IrTypeAliasImpl.<init>(IrTypeAliasImpl.kt:48)
at ...IrDeclarationDeserializer.deserializeIrTypeAlias...
at ...KotlinIrLinker.deserializeOrResolveDeclaration...
at org.jetbrains.kotlin.ir.backend.js.KlibKt.getIrModuleInfoForKlib(klib.kt:299)
at org.jetbrains.kotlin.cli.pipeline.web.wasm.WasmBackendPipelinePhase...
Important detail: the compileKotlinWasmJs task (producing the project's klib) succeeds. The failure is at the executable link step (compileDevelopmentExecutableKotlinWasmJs / wasmJsBrowserDevelopmentRun). On JVM/Android the same duplication is tolerated (class-file metadata, no klib linking), so it is wasmJs-specific.
How it was diagnosed
- Dependency report shows a single resolved datetime version (
0.7.1-0.6.x-compat -> 0.8.0), so it is not a two-versions-on-classpath problem.
- Dumping the exact klibs handed to the wasm linker
(-Pkotlin.internal.compiler.arguments.log.level=warning) shows exactly one kotlinx-datetime-wasm-js-0.8.0.klib.
unzip -p okio-fakefilesystem-wasm-js-3.17.0.klib | strings | grep -i datetime shows it references kotlinx.datetime.Clock / kotlinx.datetime.Instant (deprecated FakeFileSystem(kotlinx.datetime.Clock) ctor; FileMetadata(… kotlinx.datetime.Instant? …)), and its manifest depends= lists org.jetbrains.kotlinx:kotlinx-datetime. That is the second binder of the kotlinx.datetime/Clock signature.
Minimal reproduction
A KMP app with a wasmJs { binaries.executable() } target and:
commonMain.dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.8.0")
implementation("com.squareup.okio:okio-fakefilesystem:3.17.0")
}
Then run ./gradlew :app:wasmJsBrowserDevelopmentWebpack (Kotlin 2.4.0). JVM target links fine; wasmJs fails with the error above.
Workaround (consumer side)
Exclude the artifact from the wasmJs link path:
configurations
.matching { it.name.startsWith("wasmJs") }
.configureEach { exclude(group = "com.squareup.okio", module = "okio-fakefilesystem") }
(Only viable when FakeFileSystem isn't used in the wasm binary.) Forcing/resolving kotlinx-datetime to a single version does not help, because the incompatible class reference is baked into the published okio-fakefilesystem klib.
Possible fixes (okio side)
- Publish
okio-fakefilesystem built against the regular kotlinx-datetime (typealias to kotlin.time.*) for the klib targets, instead of the -0.6.x-compat artifact; or
- Drop the deprecated
kotlinx.datetime.Clock constructor / kotlinx.datetime.Instant surface on klib targets so the okio-fakefilesystem klib no longer references kotlinx.datetime/Clock as a class.
Self-contained reproduction project
Three files. Run ./gradlew compileDevelopmentExecutableKotlinWasmJs → fails with the error above.
(./gradlew compileKotlinJvm succeeds, demonstrating it is wasmJs-link-specific.)
settings.gradle.kts
rootProject.name = "okio-wasm-clock-repro"
pluginManagement {
repositories {
google()
gradlePluginPortal()
mavenCentral()
}
}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
build.gradle.kts
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
plugins {
kotlin("multiplatform") version "2.4.0"
}
kotlin {
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
binaries.executable()
nodejs()
}
jvm()
sourceSets {
commonMain.dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.8.0")
implementation("com.squareup.okio:okio-fakefilesystem:3.17.0")
}
}
}
src/commonMain/kotlin/Main.kt
// okio-fakefilesystem only needs to be on the link path to trigger the failure;
// this reference just makes the dependency "used" so nothing prunes it.
import okio.fakefilesystem.FakeFileSystem
fun main() {
println(FakeFileSystem())
}
Expected: clean link. Actual: wasmJs executable link fails with
IrTypeAliasSymbolImpl is already bound. Signature: kotlinx.datetime/Clock.
Related: #1740, #1689, #1660. Same error class seen downstream in supabase-community/supabase-kt#1021.
General info
What happens
okio-fakefilesystem:3.17.0declares a dependency onorg.jetbrains.kotlinx:kotlinx-datetime:0.7.1-0.6.x-compat, i.e. the artifact that keepskotlinx.datetime.Clock/kotlinx.datetime.Instantas concrete classes. The publishedokio-fakefilesystem-wasm-jsklib was therefore compiled with references to signaturekotlinx.datetime/Clock(and…/Instant) as classes — via the deprecatedFakeFileSystem(kotlinx.datetime.Clock)constructor and thekotlinx.datetime.Instantfields onFileMetadata.An application that uses the regular
kotlinx-datetime:0.8.0getskotlinx.datetime.Clockas a typealias tokotlin.time.Clockat the same signature. Gradle resolves a single datetime version (0.8.0), so there are not "two versions" on the classpath — but the wasmJs IR linker still binds signaturekotlinx.datetime/Clocktwice (once as the class reference deserialized fromokio-fakefilesystem, once as the typealias fromkotlinx-datetime:0.8.0) and fails:Important detail: the
compileKotlinWasmJstask (producing the project's klib) succeeds. The failure is at the executable link step (compileDevelopmentExecutableKotlinWasmJs/wasmJsBrowserDevelopmentRun). On JVM/Android the same duplication is tolerated (class-file metadata, no klib linking), so it is wasmJs-specific.How it was diagnosed
0.7.1-0.6.x-compat -> 0.8.0), so it is not a two-versions-on-classpath problem.(
-Pkotlin.internal.compiler.arguments.log.level=warning) shows exactly onekotlinx-datetime-wasm-js-0.8.0.klib.unzip -p okio-fakefilesystem-wasm-js-3.17.0.klib | strings | grep -i datetimeshows it referenceskotlinx.datetime.Clock/kotlinx.datetime.Instant(deprecatedFakeFileSystem(kotlinx.datetime.Clock)ctor;FileMetadata(… kotlinx.datetime.Instant? …)), and its manifestdepends=listsorg.jetbrains.kotlinx:kotlinx-datetime. That is the second binder of thekotlinx.datetime/Clocksignature.Minimal reproduction
A KMP app with a
wasmJs { binaries.executable() }target and:commonMain.dependencies { implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.8.0") implementation("com.squareup.okio:okio-fakefilesystem:3.17.0") }Then run
./gradlew :app:wasmJsBrowserDevelopmentWebpack(Kotlin 2.4.0). JVM target links fine; wasmJs fails with the error above.Workaround (consumer side)
Exclude the artifact from the wasmJs link path:
configurations .matching { it.name.startsWith("wasmJs") } .configureEach { exclude(group = "com.squareup.okio", module = "okio-fakefilesystem") }(Only viable when
FakeFileSystemisn't used in the wasm binary.) Forcing/resolvingkotlinx-datetimeto a single version does not help, because the incompatible class reference is baked into the publishedokio-fakefilesystemklib.Possible fixes (okio side)
okio-fakefilesystembuilt against the regularkotlinx-datetime(typealias tokotlin.time.*) for the klib targets, instead of the-0.6.x-compatartifact; orkotlinx.datetime.Clockconstructor /kotlinx.datetime.Instantsurface on klib targets so theokio-fakefilesystemklib no longer referenceskotlinx.datetime/Clockas a class.Self-contained reproduction project
Three files. Run
./gradlew compileDevelopmentExecutableKotlinWasmJs→ fails with the error above.(
./gradlew compileKotlinJvmsucceeds, demonstrating it is wasmJs-link-specific.)settings.gradle.ktsbuild.gradle.ktssrc/commonMain/kotlin/Main.ktExpected: clean link. Actual: wasmJs executable link fails with
IrTypeAliasSymbolImpl is already bound. Signature: kotlinx.datetime/Clock.Related: #1740, #1689, #1660. Same error class seen downstream in supabase-community/supabase-kt#1021.