# java.lang.StackOverflowError: stack size 8MB at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd

- **ID:** `android/compose-recomposition-infinite-loop`
- **Domain:** android
- **Category:** runtime_error
- **Verification:** ai_generated
- **Fix Rate:** 86%

## Root Cause

Infinite recomposition loop in Jetpack Compose due to a state variable being updated during composition (e.g., calling setState inside a LaunchedEffect without proper key or in a composable lambda that triggers re-render).

## Version Compatibility

| Version | Status | Introduced | Deprecated |
|---------|--------|------------|------------|
| Compose BOM 2024.01.00 | active | — | — |
| Compose Compiler 1.5.8 | active | — | — |
| Kotlin 1.9.22 | active | — | — |
| Android 14 (API 34) | active | — | — |

## Workarounds

1. **Move the state update outside of composition by using LaunchedEffect with a stable key. Example: LaunchedEffect(Unit) { delay(100); myState.value = newValue } instead of LaunchedEffect(myState.value) { ... }** (90% success)
   ```
   Move the state update outside of composition by using LaunchedEffect with a stable key. Example: LaunchedEffect(Unit) { delay(100); myState.value = newValue } instead of LaunchedEffect(myState.value) { ... }
   ```
2. **Use remember with a derivedStateOf to compute values without triggering recomposition. Example: val derivedValue by remember { derivedStateOf { computeExpensive(myState.value) } }** (85% success)
   ```
   Use remember with a derivedStateOf to compute values without triggering recomposition. Example: val derivedValue by remember { derivedStateOf { computeExpensive(myState.value) } }
   ```
3. **Add a snapshotFlow block to observe state changes outside composition. Example: LaunchedEffect(Unit) { snapshotFlow { myState.value }.collect { /* update other state */ } }** (88% success)
   ```
   Add a snapshotFlow block to observe state changes outside composition. Example: LaunchedEffect(Unit) { snapshotFlow { myState.value }.collect { /* update other state */ } }
   ```

## Dead Ends

- **Increase stack size via AndroidManifest android:largeHeap="true"** — largeHeap increases heap memory, not stack size. Stack size is fixed per thread in Android (8MB default). This does not fix the infinite loop. (95% fail)
- **Wrap the state update in withFrameMillis or withFrameNanos** — These APIs schedule work on the next frame but do not prevent the recomposition loop if the state is still updated during composition. (80% fail)
