Skip to content

okio-fakefilesystem 3.17.0 (compiled against kotlinx-datetime:*-0.6.x-compat) fails to link on wasmJs with IrTypeAliasSymbolImpl is already bound when the app uses kotlinx-datetime 0.8.0 #1818

Description

@mipastgt

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

  1. 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.
  2. 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.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions