expo/expo · error · ForegroundServiceStartNotAllowedException

Couldn't start the foreground service. Foreground service ca

Error message

Couldn't start the foreground service. Foreground service cannot be started when the application is in the background

What it means

expo-location throws this when you ask it to start a location task configured with a `foregroundService` option while the Android app process is not in the foreground. Android 12+ (API 31) forbids apps from starting foreground services from the background, so the module checks AppForegroundedSingleton before registering the task and fails fast with ForegroundServiceStartNotAllowedException instead of letting the OS kill the start attempt.

Source

Thrown at packages/expo-location/android/src/main/java/expo/modules/location/LocationModule.kt:331

    AsyncFunction<Boolean>("hasServicesEnabledAsync") {
      return@AsyncFunction LocationHelpers.isAnyProviderAvailable(mContext)
    }

    AsyncFunction("startLocationUpdatesAsync") { taskName: String, options: LocationTaskOptions ->
      val shouldUseForegroundService = options.foregroundService != null

      if (isMissingForegroundPermissions()) {
        throw LocationBackgroundUnauthorizedException()
      }
      // There are two ways of starting this service.
      // 1. As a background location service, this requires the background location permission.
      // 2. As a user-initiated foreground service with notification, this does NOT require the background location permission.
      if (!shouldUseForegroundService && isMissingBackgroundPermissions()) {
        throw LocationBackgroundUnauthorizedException()
      }
      if (!AppForegroundedSingleton.isForegrounded && options.foregroundService != null) {
        throw ForegroundServiceStartNotAllowedException()
      }

      if (shouldUseForegroundService && !hasForegroundServicePermissions()) {
        throw ForegroundServicePermissionsException()
      }

      mTaskManager.registerTask(taskName, LocationTaskConsumer::class.java, options.toMutableMap())
      return@AsyncFunction
    }

    AsyncFunction("stopLocationUpdatesAsync") { taskName: String ->
      mTaskManager.unregisterTask(taskName, LocationTaskConsumer::class.java)
      return@AsyncFunction
    }

    AsyncFunction("hasStartedLocationUpdatesAsync") { taskName: String ->
      return@AsyncFunction mTaskManager.taskHasConsumerOfClass(taskName, LocationTaskConsumer::class.java)
    }

View on GitHub (pinned to 7da61120be)

Solutions

  1. Ensure the call runs only while the app is foregrounded: check AppState/AppLifecycle state before calling and defer the start until the activity resumes.
  2. Remove the `foregroundService` option (use plain background location with BACKGROUND_LOCATION permission) if updates must start from the background.
  3. Start the service from a user-visible interaction (notification button, activity) rather than a background callback.
  4. On Android 12+, if a legitimate background start is needed, have the user grant exact-alarm/exemption paths or use a foregroundServiceType-compatible restart via the system (e.g. from an existing foreground service context).

Example fix

// before
await Location.startLocationUpdatesAsync(TASK, {
  foregroundService: { notificationTitle: 'Tracking' },
});

// after
if (AppState.currentState !== 'active') {
  // defer until foregrounded, or drop foregroundService
  return;
}
await Location.startLocationUpdatesAsync(TASK, {
  foregroundService: { notificationTitle: 'Tracking' },
});
Defensive patterns

Strategy: try-catch

Validate before calling

import { AppState } from 'react-native';
function canStartForegroundLocation() {
  return AppState.currentState === 'active';
}

Try / catch

try {
  await Location.startLocationUpdatesAsync(TASK, { foregroundService: opts });
} catch (e) {
  if (String(e.message).includes('Foreground service cannot be started when the application is in the background')) {
    // defer until app returns to foreground
    AppState.addEventListener('change', (s) => { if (s === 'active') restart(); });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling Location.startLocationUpdatesAsync / startLocationTaskAsync with `foregroundService: {...}` set while ActivityManager.getRunningAppProcesses reports the app is not foregrounded — e.g. invoked from a headless task manager callback, background fetch, or a notification tap handler that runs before the activity resumes.

Common situations: Restarting continuous location tracking from a background task after the OS killed the app; scheduling location updates from a push handler; a JS timer or task-manager callback firing after the user backgrounds the app; testing on Android 12+ emulators where the activity is not focused.

Related errors


AI-assisted analysis of expo/expo@7da61120be (2026-09-09). Data as JSON: /api/errors/bb70f949483615bc. Report an issue: GitHub.