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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions