Status Update
Comments
fe...@aspire.se <fe...@aspire.se> #2
After upgrading to kotlin 2.1.0 and bumping remaining dependencies, things seem to work as expected again. EDIT: My bad; was on the wrong branch. Those upgrades did NOT help.
fe...@aspire.se <fe...@aspire.se> #3
I think I managed to track it down further:
In my Child
composable, I'm actually hitting a TODO()
statement:
@Composable
fun Child(isLoading: Boolean, items: List<MyDataClass>) {
// ...
if (notYetSupported) {
TODO("This is not yet supported!")
}
// ...
}
It would seem that compose swallows this error and throws the above instead which is not very helpful.
an...@google.com <an...@google.com> #4
The "pending composition has not been applied" error generally means that composition continued despite something in the hierarchy previously throwing an exception. Here it looks like something is continuing a subcomposition unexpectedly, possibly a LazyList.
We should see if we can improve this error messaging. Can you send over a more complete example? The snippets here aren't fleshed out enough to reproduce this swallowing behavior.
al...@google.com <al...@google.com> #5
Triage notes: It feels like we're very close to having a repro case that we could run internally, but we don't know where the sub-composition is coming from.
Can you send over a more complete example?
Let's hold until we can get a stable repro case from the reporter. Could you send us a ZIP of the project that repros this issue? We'll close this out in a month if we don't get a response.
Bugjuggler: wait 1 month
bu...@google.com <bu...@google.com> #6
fe...@aspire.se <fe...@aspire.se> #7
This took me about an hour to extract but it reproduces the issue for me.
@file:SuppressLint("UnusedMaterialScaffoldPaddingParameter")
package com.example
import android.annotation.SuppressLint
import android.app.Application
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import kotlinx.coroutines.delay
class MyApp : Application()
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
// Scaffold is required!
Scaffold { _ ->
val a = remember { mutableStateOf(true) }
val b = remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
a.value = false
delay(50)
b.value = false
}
AnimatedVisibility(visible = a.value) { Text("Hello World") }
if (!b.value) {
TODO()
}
}
}
}
}
}
al...@google.com <al...@google.com>
an...@google.com <an...@google.com> #8
Thank you! I was able to reproduce locally. Will look into this. We may eventually dedupe to
One thing to note is that this is definitely related to a race condition. Device speed matters, and a slower device seems more likely to trigger this exception — My aging Pixel XL from 2016 reproduces this very consistently, unlike my local emulator which doesn't demonstrate this issue at all. We had suspected that coroutines were coming into play here, so a lot of pieces are starting to come together.
an...@google.com <an...@google.com> #9
Correction: The emulator I was using had animations disabled. This seems to reproduce very consistently across devices.
It looks like our exception handling logic is try/catching Exception
instead of Throwable
. TODO() is breaking things because it throws a NotImplementedError
, which isn't caught by our error handler and doesn't cancel pending recompositions. We'll update our code to include Errors and generic Throwable classes. It's not immediately obvious if this will fix other occurrences of this exception since we don't have other reproduction cases.
ap...@google.com <ap...@google.com> #10
Project: platform/frameworks/support
Branch: androidx-main
Author: Andrew Bailey <
Link:
Fix Throwables causing unapplied composition error
Expand for full commit details
Fix Throwables causing unapplied composition error
The error handling logic in the Recomposer was set up to catch
throwables that extended from Exception, which excluded Errors (like
NotImplementedError, error(""), StackOverflowError, etc.) and
user-defined exceptions that extend directly from Throwable. This CL
updates the relevant pathways to switch over all Throwables.
This resolves at least one pathway that leads to a "Pending composition
has not been applied." runtime error. It's not immediately clear if this
accounts for all of the reports since we only have one known
reproduction case right now.
Test: Manually run repro case in the linked bug
Fixes: b/382094412
Relnote: """
Fixes an issue where raising a throwable during composition that
does not extend from Exception may lead to a 'Pending composition
has not been applied' error.
"""
Change-Id: I356be5d99df41138be790275807544b2d717050c
Files:
- M
compose/runtime/runtime/api/current.txt
- M
compose/runtime/runtime/api/restricted_current.txt
- M
compose/runtime/runtime/integration-tests/src/androidInstrumentedTest/kotlin/androidx/compose/runtime/LiveEditApiTests.kt
- M
compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/HotReloader.kt
- M
compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
- M
compose/runtime/runtime/src/nonEmulatorJvmTest/kotlin/androidx/compose/runtime/LiveEditTests.kt
Hash: 120c3f0cfa04436bd9afabea415a478e12458316
Date: Wed Jan 08 15:38:34 2025
Description
Jetpack Compose version:
BOM
2023.10.01
,2024.11.00
Jetpack Compose component(s) used:
androidx.activity:activity-compose
androidx.compose.material:material
androidx.compose.material:material-icons-extended
androidx.compose.ui:ui
androidx.compose.ui:ui-graphics
androidx.navigation:navigation-compose
androidx.constraintlayout:constraintlayout-compose
Android Studio Build:
Kotlin version:
1.9.22
Steps to Reproduce or Code Sample to Reproduce:
I don't really have a reproduction available at this time. The following is an untested simplification where I'd start writing a new repro from. Also, be aware that this code is executing from a dynamic feature module.
Stack trace (if applicable):