Side Effect Bugs

Common Side Effect Bugs and How to Avoid Them

The classic bug is a stale capture: an effect keyed on Unit keeps its first lambda. Both timers log label, and Change promo switches it to "Clearance" before they fire:

EffectDemos.kt: a stale capture and its fixKotlin
@Composable
fun StaleTimer(onTimeout: () -> Unit) {
  LaunchedEffect(Unit) { delay(3000); onTimeout() }   // keeps the first lambda forever
}
@Composable
fun FreshTimer(onTimeout: () -> Unit) {
  val latest by rememberUpdatedState(onTimeout)       // updated on every recomposition
  LaunchedEffect(Unit) { delay(3000); latest() }
}
Output
D/BookNestFx: stale timer sees 'Autumn sale'
D/BookNestFx: fresh timer sees 'Clearance'

rememberUpdatedState reads the latest value without restarting, like React 19.2 7,897 's useEffectEvent. Other bugs that compile: scope.launch in a composable's body repeats on every recomposition (use LaunchedEffect), a value read but not keyed leaves old data on screen, and catch (e: Exception) swallows cancellation. Rotate each screen and navigate away and back to flush out missing cleanup.