getsentry / getsentry/sentry-java
NoSuchMethodError in SentryTraced on Compose < 1.8 (inlined Box pulls in newer internals)
- Ngôn ngữ chính
- Kotlin
- Star
- 1.4k
- Fork
- 478
- Merge trung bình
- 2 ngày 23 giờ
- Pull request đã merge (30 ngày)
- 67
Mô tả
## Summary
`sentry-compose` ships bytecode that references Jetpack Compose *internal* APIs newer than the SDK's own declared Compose floor (`androidxCompose = "1.6.3"` in `gradle/libs.versions.toml`). Apps resolving an older Compose crash with `NoSuchMethodError` when composing `SentryTraced`.
Sentry issue: [SDK-CRASHES-JAVA-48AR]() — 157 occurrences, first seen 2026-03-19, reported on release 8.51.0.
## Root cause
`androidx.compose.foundation.layout.Box` is an **inline** composable. The Compose compiler bakes its body into *our* bytecode, so `sentry-compose` calls Compose internals directly rather than calling `BoxKt.Box`. The published 8.51.0 `SentryComposeTracingKt` contains zero `BoxKt.Box` call sites and instead references:
| Symbol | First available in |
| -- | -- |
| `BoxKt.maybeCachedBoxMeasurePolicy` | foundation-layout **1.7.0** |
| `Composer.shouldExecute` | runtime **1.8.0** |
Neither exists on Compose 1.6.x, so the call fails at runtime at the `SentryTraced` frame.
`SentryUserFeedbackButtonKt` is affected the same way (it also emits `shouldExecute` / `materializeModifier`).
## How it regressed
`sentry-compose/build.gradle.kts` declares `compileOnly(libs.androidx.compose.material3)`. In #5017 (*"Convert main screen to Jetpack Compose"* — a **samples** refactor) material3 was bumped `1.2.1 -> 1.4.0`. material3 1.4.0 transitively pulls foundation-layout 1.8.1 and runtime 1.9.0 onto `sentry-compose`'s compile classpath, silently raising the floor of the inlined code.
Confirmed by bisecting published artifacts on Maven Central:
* 8.31.0 and earlier -> `rememberBoxMeasurePolicy` (works on 1.6.x)
* **8.32.0** onward -> `maybeCachedBoxMeasurePolicy` + `shouldExecute`
## Note on the Seer suggestion
Seer's autofix suggests removing `propagateMinConstraints = true` from the `Box` in `SentryTraced`. **This is incorrect.** `BoxKt`'s public signature is byte-for-byte identical from foundation-layout 1.5.4 through 1.11.2 — `propagateMinConstraints` has always been a parameter. Removing it would change layout behavior (regressing #2637) without fixing the crash.
## Proposed fix
Decouple `sentry-compose`'s compile-time Compose floor from material3. Add a dedicated version-catalog entry pinned to the oldest supported material3 and use it only for `sentry-compose`'s `compileOnly`, mirroring the existing `androidx-compose-ui-replay` entry (which already carries a *"don't change without testing forwards compatibility"* comment):
```kotlin
// sentry-compose/build.gradle.kts
compileOnly(libs.androidx.compose.material3.compat) // pinned to 1.2.1
```
Pinning `libs.androidx.compose.material3` globally is not viable — the samples depend on newer material3 APIs and material icons.
### Verified locally
Compiling `sentry-compose` with material3 pinned to 1.2.1:
* `:sentry-compose:compileReleaseKotlinAndroid` succeeds
* emitted bytecode reverts to `rememberBoxMeasurePolicy`, and `shouldExecute` / `materializeModifier` are gone from both affected classes
* `rememberBoxMeasurePolicy` is present in foundation-layout 1.5.4 through 1.11.2, so it is both backward and forward compatible
## Follow-up: add a regression guard
Nothing in CI asserts the supported Compose floor, which is why this shipped silently and went unnoticed for ~19 releases. We should add a guard so the next transitive bump can't reintroduce it — either a check that resolves the floor versions, or an assertion over the compiled bytecode for newer-than-floor internal symbols.
## Open decision
Alternative: **raise** the documented floor to Compose 1.8.0 instead of restoring 1.6.3 compatibility. That is simpler, but is a breaking change for users on older Compose and needs a changelog entry and an explicit minimum-version statement.
Hướng dẫn đóng góp
Đánh giá
Issue này chưa được đánh giá.