Force-Close Errors on Android: Diagnosis and Fix Guide
Force-close is Android's visible way of saying "I gave up on this app." The system shows "App has stopped" — users lose whatever they were doing. Unlike ANRs (frozen UI) or native crashes, force-close
Force-close is Android's visible way of saying "I gave up on this app." The system shows "App has stopped" — users lose whatever they were doing. Unlike ANRs (frozen UI) or native crashes, force-close often has a diagnosable stack trace. This guide covers how to find it and fix.
What force-close actually means
An unhandled exception bubbled up to the runtime. The ActivityManager kills the process and shows the dialog. From Android 11+, the dialog is slimmer ("App keeps stopping"), but the root cause is the same.
Different from:
- ANR: thread busy, not crashed. UI frozen.
- OOM kill: OS kills background app to reclaim memory. No dialog; user sees "app closed" if foregrounded.
- Native crash: SIGSEGV / SIGABRT in native code. Slightly different UI.
Common causes
1. NullPointerException
val name = user.name and user is null. Classic.
Fix: Kotlin null-safety. Use ?. and ?:. In Java, explicit null checks.
2. Unhandled callback on destroyed activity
Activity finished. 5 seconds later, network callback fires. Code tries to setTitle(...) on destroyed activity → IllegalStateException.
Fix: Use lifecycleScope (coroutines) or LiveData (survives rotation). Check isFinishing before UI updates.
3. Fragment transaction after saveInstanceState
fragmentManager.beginTransaction()...commit() after onSaveInstanceState → IllegalStateException: Can not perform this action after onSaveInstanceState.
Fix: commitAllowingStateLoss() when appropriate. Or defer transactions to onResume.
4. BadTokenException on dialog
Dialog shown on destroyed activity's context → crash.
Fix: Check activity state before showing dialogs. Use fragment lifecycle.
5. Network on main thread
NetworkOnMainThreadException. Blocks UI and gets punished.
Fix: Every network call on background thread. Coroutines / WorkManager / Retrofit-with-async.
6. ClassCastException
Bundle contains a Serializable or Parcelable the receiving code casts incorrectly.
Fix: Consistent types across producer and consumer. Type-safe navigation arguments.
7. StrictMode violations
With StrictMode on, violations crash instead of log. Forgotten disk read on main thread → crash.
Fix: Disable StrictMode penalty on release, or fix the violations.
8. Permission check missing
contentResolver.query(CONTACTS_URI, ...) without READ_CONTACTS permission → SecurityException.
Fix: Check permission before API call.
9. ForegroundService start-from-background (Android 12+)
Starting foreground service from background without proper conditions → ForegroundServiceStartNotAllowedException.
Fix: Meet Android 12+ foreground service restrictions. Start only when allowed; consider WorkManager alternative.
10. Notification permission missing (Android 13+)
Posting notification without POST_NOTIFICATIONS permission → silent no-op or SecurityException depending on context.
Fix: Request permission at runtime.
Diagnosis
Stack trace
adb logcat -s AndroidRuntime:E captures the exception and stack at crash time. Top-of-stack is your culprit.
Field data
Crashlytics / Sentry / Bugsnag clusters crashes by signature. Filter by:
- Device / OS version
- App version
- User action leading to crash (breadcrumbs)
Reproduction
- Steps from field users (or breadcrumbs)
- Try on clean / stateful / rotated / backgrounded devices
- StrictMode on to surface main-thread violations
Fix patterns
- Null-safety everywhere. Kotlin makes this easy. Enable
-Xexplicit-api=strictin libraries. - Lifecycle-aware code. Everything tied to view/activity has a lifecycle scope.
- Bounded exception handling at boundaries. API call failures caught, not let bubble to UI.
- Testing across configurations. Rotation, low memory, fast navigation, back-stack edge cases.
- StrictMode in debug. Catch main-thread violations in development.
- ProGuard/R8 correctness. Release builds differ from debug. Test the release APK.
How SUSA catches these
SUSA monitors logcat continuously. Any AndroidRuntime error during exploration is captured with full stack, timestamp, action being taken, screenshot, and session context. Personas like adversarial deliberately stress patterns (rapid taps, rotations, back-spam) that surface lifecycle crashes.
susatest-agent test myapp.apk --persona adversarial --steps 200
Crash rate target: under 0.5% foreground crash-free users. Anything above 1% is actively losing you users. Investment in fixing force-closes always pays back.
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free