ComposePausableCompositionException and IllegalStateException: Apply is called on deactivated node when fast scrolling LazyColumn with Coil AsyncImage
Hello everyone,
I am experiencing a persistent crash in my Jetpack Compose project while using Coil (AsyncImage) inside a LazyColumn. The data is being observed from a remote service via Flow.
The crash specifically occurs during high-speed scrolling (stress testing). After several trials, I isolated the issue and confirmed that the crash only happens when AsyncImage is present. Replacing it with a standard Image or Box resolves the issue, which points to a race condition within Coil’s internal measurement logic.
Environment:
Compose BOM: 2026.02.01
Coil Version: 2.2.2
Kotlin Version: 2.0.21
Compiler: Kotlin 2.0 Compose Compiler
Code :
@Composable
fun CountryCardItem(
country: CountryItem,
onCountryClick: (String) -> Unit
) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = Dimens.dp16, vertical = Dimens.dp6)
.clip(shape = RoundedCornerShape(Dimens.dp12))
.clickable { onCountryClick(country.name.toString()) },
shape = RoundedCornerShape(Dimens.dp12),
elevation = CardDefaults.cardElevation(defaultElevation = Dimens.dp2),
colors = CardDefaults.cardColors(containerColor = Color.White)
) {
Row(
modifier = Modifier
.padding(Dimens.dp12)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
AsyncImage(
model = country.flag?.png,
contentDescription = "${country.name} Flag",
modifier = Modifier
.size(Dimens.dp56)
.clip(RoundedCornerShape(Dimens.dp12)),
contentScale = ContentScale.Crop,
)
Spacer(modifier = Modifier.width(Dimens.dp16))
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = country.name ?: "Unknown",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary,
)
Text(
text = country.capital ?: "No Capital",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.secondary,
)
}
Icon(
painter = painterResource(R.drawable.ic_arrow_right),
contentDescription = "Go to details",
tint = MaterialTheme.colorScheme.surfaceVariant,
modifier = Modifier.size(Dimens.dp24)
)
}
}
}
Full Exception Code :
androidx.compose.runtime.ComposePausableCompositionException: Failed to execute op number 24
0: down LayoutNode@ec918ec children: 1 measurePolicy: BoxMeasurePolicy(alignment=BiasAlignment(horizontalBias=-1.0, verticalBias=-1.0), propagateMinConstraints=true) deactivated: false
1: reuse LayoutNode@ec918ec children: 1 measurePolicy: BoxMeasurePolicy(alignment=BiasAlignment(horizontalBias=-1.0, verticalBias=-1.0), propagateMinConstraints=true) deactivated: false
2: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.ui.layout.MeasurePolicy, kotlin.Unit>
3: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.runtime.CompositionLocalMap, kotlin.Unit>
4: apply Function2<androidx.compose.ui.node.ComposeUiNode, java.lang.Integer, kotlin.Unit>
5: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.ui.Modifier, kotlin.Unit>
6: down LayoutNode@aad474a children: 1 measurePolicy: ColumnMeasurePolicy(verticalArrangement=Arrangement#Top, horizontalAlignment=Horizontal(bias=-1.0)) deactivated: false
7: reuse LayoutNode@aad474a children: 1 measurePolicy: ColumnMeasurePolicy(verticalArrangement=Arrangement#Top, horizontalAlignment=Horizontal(bias=-1.0)) deactivated: false
8: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.ui.layout.MeasurePolicy, kotlin.Unit>
9: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.runtime.CompositionLocalMap, kotlin.Unit>
10: apply Function2<androidx.compose.ui.node.ComposeUiNode, java.lang.Integer, kotlin.Unit>
11: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.ui.Modifier, kotlin.Unit>
12: down LayoutNode@4bc16bb children: 4 measurePolicy: RowMeasurePolicy(horizontalArrangement=Arrangement#Start, verticalAlignment=Vertical(bias=0.0)) deactivated: false
13: reuse LayoutNode@4bc16bb children: 4 measurePolicy: RowMeasurePolicy(horizontalArrangement=Arrangement#Start, verticalAlignment=Vertical(bias=0.0)) deactivated: false
14: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.ui.layout.MeasurePolicy, kotlin.Unit>
15: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.runtime.CompositionLocalMap, kotlin.Unit>
16: apply androidx.compose.runtime.Updater$$ExternalSyntheticLambda1@22aca1
17: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.ui.Modifier, kotlin.Unit>
18: down LayoutNode@b99b0c0 children: 0 measurePolicy: coil.compose.AsyncImageKt$Content$1@4e2bec6 deactivated: false
19: reuse LayoutNode@b99b0c0 children: 0 measurePolicy: coil.compose.AsyncImageKt$Content$1@4e2bec6 deactivated: false
20: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.ui.Modifier, kotlin.Unit> 21: up
22: down LayoutNode@2a4d7d8 children: 0 measurePolicy: androidx.compose.foundation.layout.SpacerMeasurePolicy@b74cc8f deactivated: true 23: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.runtime.CompositionLocalMap, kotlin.Unit> 24: apply androidx.compose.runtime.Updater$$ExternalSyntheticLambda1@dcfbe87
25: up
26: down LayoutNode@a008e16 children: 2 measurePolicy: ColumnMeasurePolicy(verticalArrangement=Arrangement#Top, horizontalAlignment=Horizontal(bias=-1.0)) deactivated: true
27: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.runtime.CompositionLocalMap, kotlin.Unit>
28: apply androidx.compose.runtime.Updater$$ExternalSyntheticLambda1@eb71b4
29: down LayoutNode@8caf1f9 children: 0 measurePolicy: androidx.compose.foundation.text.EmptyMeasurePolicy@61c71dd deactivated: true 30: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.runtime.CompositionLocalMap, kotlin.Unit> 31: apply androidx.compose.runtime.Updater$$ExternalSyntheticLambda1@2bc0152 32: apply Function2<androidx.compose.ui.node.ComposeUiNode, androidx.compose.ui.Modifier, kotlin.Unit>
.....
Caused by: java.lang.IllegalStateException: Apply is called on deactivated node LayoutNode@a5829de children: 0 measurePolicy: androidx.compose.foundation.layout.SpacerMeasurePolicy@fabdd40 deactivated: true at androidx.compose.ui.node.ComposeUiNode$Companion$ApplyOnDeactivatedNodeAssertion$1.invoke(ComposeUiNode.kt:54)
The Problem and Diagnosis**
When using Coil's AsyncImage within a LazyColumn in Jetpack Compose, the application may crash under rapid scrolling conditions with the following errors:
androidx.compose.runtime.ComposePausableCompositionException: Failed to execute op number 24
java.lang.IllegalStateException: Apply is called on deactivated node
Diagnostic Process: To isolate the root cause, I performed systematic trial-and-error testing. I discovered that removing AsyncImage and replacing it with a standard Box or Image completely eliminated the crashes. This proved the issue stems directly from AsyncImage's internal rendering and measurement mechanics.
ConstraintsSizeResolver and Race ConditionThe crash is rooted in how Coil's internal ConstraintsSizeResolver class handles asynchronous size resolution.
Coil uses a LayoutModifier called ConstraintsSizeResolver to determine the image size, tracking layout constraints via a MutableStateFlow:
internal class ConstraintsSizeResolver : SizeResolver, LayoutModifier {
private val _constraints = MutableStateFlow(ZeroConstraints)
// Flow'un ilk geçerli değeri üretmesini bekler (Asenkron)
override suspend fun size() = _constraints.mapNotNull(Constraints::toSizeOrNull).first()
override fun MeasureScope.measure(measurable: Measurable, constraints: Constraints): MeasureResult {
// Cache the current constraints.
_constraints.value = constraints
val placeable = measurable.measure(constraints)
return layout(placeable.width, placeable.height) { placeable.place(0, 0) }
}
}
During rapid scrolling, LazyColumn immediately "deactivates" (recycles) LayoutNodes that leave the screen to maintain performance. However, Coil's size() function may still be waiting for the Flow to emit the initial size or attempting to apply changes when the node is already deactivated.
The error Caused by: java.lang.IllegalStateException: Apply is called on deactivated node indicates a race condition. Compose runtime throws this exception to prevent a safe-critical state when Coil's asynchronous flow tries to apply changes to a disposed or deactivated node.
This issue can be mitigated using one of three strategies:
rememberAsyncImagePainter + Image (Recommended)This is the most stable and performant solution for fast-scrolling lists. By using rememberAsyncImagePainter, you entirely bypass AsyncImage's complex subcomposition and asynchronous flow-based constraint resolution mechanics.
ContentScale.NoneIf you analyze Coil's updateRequest method, setting contentScale to None forces Coil to use SizeResolver(CoilSize.ORIGINAL) (fixed size). This prevents the asynchronous ConstraintsSizeResolver from ever being instantiated:
@Composable
internal fun updateRequest(request: ImageRequest, contentScale: ContentScale): ImageRequest {
return if (request.defined.sizeResolver == null) {
val sizeResolver = if (contentScale == ContentScale.None) {
SizeResolver(CoilSize.ORIGINAL)
} else {
remember { ConstraintsSizeResolver() } // The risky one
}
request.newBuilder().size(sizeResolver).build()
} else {
request // Safe if sizeResolver is already defined
}
}
.size() in ImageRequestIf you define a fixed size in your ImageRequest (e.g., .size(200)), Coil already knows the target size. As shown in the code block above, the if (request.defined.sizeResolver == null) check will fail, and it will directly enter the safe else { request } block, entirely bypassing the flawed asynchronous calculation process.