WorkManager on Android 14 to 17: Fixing ForegroundServiceStartNotAllowedException & Execution Crashes
Modern Android tightened foreground service (FGS) rules, and many apps that “worked fine” on Android 12/13 started crashing on Android 14+ after targeting API 34. A common stack trace is:
- android.app.ForegroundServiceStartNotAllowedException
- IllegalStateException: Not allowed to start service … app is in background
If your Worker calls setForegroundAsync() at the wrong time, WorkManager will attempt to start its system foreground service and the process can crash on Android 14+. In this post, I’ll show how to make WorkManager-based features resilient across Android 14–17 by preventing illegal FGS starts, using expedited work where appropriate, and structuring work so it never crashes even as platform rules tighten.
This is a practical, production-focused walkthrough you can apply to ongoing uploads, long-running syncs, and similar jobs.
Prerequisites
- Android Studio 2023.3 (Jellyfish) or newer
- Kotlin 1.8+ (or newer)
- Compile/target SDK: 34 or newer
- Min SDK: per your app (examples below use 23+)
- Dependencies:
- androidx.work:work-runtime-ktx 2.9.x or newer
- androidx.core:core-ktx 1.12+ or newer
- androidx.lifecycle:lifecycle-runtime-ktx 2.6+ or newer
Note: Always prefer the latest stable AndroidX versions.
What changed on Android 14+ and why your Workers crash
- Foreground services can’t be started from the background unless the app qualifies under narrow, system-defined reasons (for example, an incoming call) or uses specific user-initiated flows. Simply scheduling a Worker and then promoting it to the foreground later (setForegroundAsync) is often illegal if the app isn’t visible.
- WorkManager’s “foreground Worker” is implemented by starting an internal service (SystemForegroundService). If Android considers your app background when that service starts, the platform throws ForegroundServiceStartNotAllowedException.
- On 14+, these checks are stricter and more consistent. Code that used to slip by now fails deterministically.
Implication: If you need FGS, start it only when the app is visible and user-initiated. Otherwise, don’t use FGS at all - use regular or expedited WorkRequests.
Choose the right tool for the job
- Immediate, short, user-initiated work (e.g., quick upload after pressing “Send”):
- Use WorkManager expedited work (setExpedited).
- No FGS needed; finishes quickly, runs immediately, but subject to quotas.
- Long-running, user-initiated work that must keep running while the UI is visible:
- You may use a foreground Worker but only start FGS while the app is visible.
- If the user backgrounds the app, gracefully continue as non-FGS Worker (no crash) or pause/resume later.
- Long-running background tasks without strict immediacy (sync, cleanup, batching):
- Use regular WorkManager with constraints; do not use FGS.
If you truly need a continuous FGS while the app is backgrounded (rare under current policy), consider a dedicated Service started lawfully from the foreground UI and ensure it qualifies for allowed cases. Don’t expect WorkManager to bypass platform restrictions.
