Skip to content

Enable Java 8+ API desugaring for API 24/25 support (Sentry COLUMBA-8M)#854

Open
torlando-tech wants to merge 1 commit into
mainfrom
fix/api24-desugar-localdatetime
Open

Enable Java 8+ API desugaring for API 24/25 support (Sentry COLUMBA-8M)#854
torlando-tech wants to merge 1 commit into
mainfrom
fix/api24-desugar-localdatetime

Conversation

@torlando-tech

Copy link
Copy Markdown
Owner

Summary

Fixes Sentry COLUMBA-8MNoClassDefFoundError: java.time.LocalDateTime on Android 7.x devices (API 24/25).

Captured stack:
```
java.lang.NoClassDefFoundError: Failed resolution of: Ljava/time/LocalDateTime;
at network.reticulum.transport.Transport.log(Transport.kt:5697)
at network.reticulum.transport.Transport.registerDestination(Transport.kt:874)
at network.reticulum.destination.Destination$Companion.create(Destination.kt:845)
at NativeReticulumProtocol.buildIdentityResult(NativeReticulumProtocol.kt:1018)
at NativeReticulumProtocol$importIdentityFile$2.invokeSuspend(NativeReticulumProtocol.kt:983)
Caused by: ClassNotFoundException: java.time.LocalDateTime
```
For the captured user this fired during identity import via the deep link `/identity_manager?base32Key={...}`, but any code path that registers a destination would crash identically.

Root cause

Upstream `reticulum-kt`'s public API references `java.time.LocalDateTime` (verified by grepping the cached jars: 8 refs in `rns-core-v0.0.12.jar`, 20 in `rns-interfaces-v0.0.12.jar`). `java.time.*` was only added to the Android runtime in API 26.

Columba's `minSdk` is 24 in every Android module, but `coreLibraryDesugaring` was not configured anywhere — zero hits across all `build.gradle.kts` files. So on API 24/25 the class loader trips the moment `Transport` touches a `LocalDateTime`-bearing method.

Fix

Enable Java 8+ API desugaring in the three Android modules (`app`, `reticulum`, `data`) and add `desugar_jdk_libs` 2.1.5 as a `coreLibraryDesugaring` dependency in each. The `domain` and `micron` modules are pure JVM (`java-library` / `kotlin("jvm")`) and don't need it.

```kotlin
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
isCoreLibraryDesugaringEnabled = true
}
```
```kotlin
dependencies {
coreLibraryDesugaring(libs.android.desugar.jdk.libs)
}
```

Affected scope

  • Devices: Android 7.x (API 24/25) — roughly the bottom ~2% of active Android.
  • Code paths: not just identity import — anything that touches `Transport` in reticulum-kt eventually hits a `LocalDateTime`-bearing method.

Test plan

  • `./gradlew :app:assembleNoSentryDebug` builds clean (BUILD SUCCESSFUL in 2m 17s)
  • No new dependencies pulled into `domain` / `micron` (verified — they're pure JVM)
  • Manual smoke on an API 24 emulator: install, import identity via deep link, confirm no NCDFE
  • Sentry COLUMBA-8M event count drops to zero on subsequent releases

Notes

  • An upstream fix in `reticulum-kt` to avoid `java.time.*` in public API would also resolve this without consumer-side desugaring, but that's a larger change. Desugaring is the safe, mechanical fix and is the standard solution for this exact scenario.
  • `desugar_jdk_libs` 2.1.5 is the current stable release; works with AGP 8.x and Kotlin 2.x.

🤖 Generated with Claude Code

@greptile-apps

greptile-apps Bot commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a NoClassDefFoundError: java.time.LocalDateTime crash on Android 7.x (API 24/25) caused by reticulum-kt's public API referencing java.time.* classes that are only natively available on API 26+.

  • Enables isCoreLibraryDesugaringEnabled = true in compileOptions for the three Android modules (app, reticulum, data) and adds coreLibraryDesugaring(libs.android.desugar.jdk.libs) to each, using the full desugar_jdk_libs 2.1.5 artifact which covers all java.time.* APIs.
  • Adds the version entry and library alias to libs.versions.toml; the pure-JVM domain and micron modules are correctly left untouched.
  • The reticulum module is the most critical recipient since it api-exposes the rns-core/rns-interfaces artifacts that carry the LocalDateTime references, making the fix transitive to :app; enabling it on :app directly as well is required for the final merged APK.

Confidence Score: 5/5

Safe to merge — this is a well-scoped, mechanical build-config change that fixes a confirmed production crash with no logic changes.

All three Android modules correctly get isCoreLibraryDesugaringEnabled = true paired with the coreLibraryDesugaring dependency. The correct full artifact (com.android.tools:desugar_jdk_libs, not the minimal variant) is chosen, which is required since java.time.LocalDateTime is in the full desugaring library. Version 2.1.5 is compatible with AGP 8.x. The pure-JVM modules are correctly excluded. The build has been verified clean by the author.

No files require special attention. The screenshot-tests module (noted in a prior review comment) does not yet depend on :reticulum, so it is unaffected for now.

Important Files Changed

Filename Overview
gradle/libs.versions.toml Adds desugarJdkLibs = "2.1.5" version and android-desugar-jdk-libs library alias pointing to com.android.tools:desugar_jdk_libs — correct artifact group/name and a stable version compatible with AGP 8.x.
reticulum/build.gradle.kts Enables isCoreLibraryDesugaringEnabled = true and adds coreLibraryDesugaring(libs.android.desugar.jdk.libs) — most critical module since it directly api-exposes rns-core/rns-interfaces which contain the java.time.LocalDateTime references.
app/build.gradle.kts Enables desugaring and adds coreLibraryDesugaring dependency; the app module consumes :reticulum so this is required for the final merged APK to work on API 24/25.
data/build.gradle.kts Desugaring enabled; data only depends on :domain (pure JVM), not :reticulum, so this is forward-proofing in case Room TypeConverters or future code uses java.time.* directly — harmless and consistent with the other modules.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph JVM["Pure JVM - no desugaring needed"]
        domain[":domain java-library"]
        micron[":micron kotlin jvm"]
    end

    subgraph Android["Android modules - isCoreLibraryDesugaringEnabled = true"]
        reticulum[":reticulum android-library"]
        data[":data android-library"]
        app[":app com.android.application"]
    end

    subgraph Upstream["reticulum-kt JitPack JARs"]
        rnscore["rns-core-v0.0.16 - 8 LocalDateTime refs"]
        rnsinterfaces["rns-interfaces-v0.0.16 - 20 LocalDateTime refs"]
    end

    rnscore -->|api| reticulum
    rnsinterfaces -->|api| reticulum
    reticulum -->|implementation| app
    data -->|implementation| app
    domain -->|implementation| data
    domain -->|implementation| app
    micron -->|implementation| app
Loading

Reviews (2): Last reviewed commit: "Enable Java 8+ API desugaring for API 24..." | Re-trigger Greptile

Sentry COLUMBA-8M: NoClassDefFoundError: java.time.LocalDateTime on
Android 7.x devices (API 24/25). The crash fires the moment Transport
.registerDestination touches a method whose signature references
LocalDateTime — for the captured user this was identity import via the
deep link /identity_manager?base32Key={...}, but any code path that
registers a destination would crash identically.

Root cause: reticulum-kt's public API surface uses java.time.* (8 refs
in rns-core, 20 in rns-interfaces). java.time was added in API 26.
Columba's minSdk is 24 across all Android modules, but no module had
coreLibraryDesugaring configured.

Enable isCoreLibraryDesugaringEnabled and add the desugar_jdk_libs
dependency in all three Android modules (app, reticulum, data). The
domain and micron modules are pure JVM and don't need it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@torlando-tech torlando-tech force-pushed the fix/api24-desugar-localdatetime branch from d790689 to 8b2a449 Compare May 8, 2026 06:55
@sentry

sentry Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant