expo: [SDK 50] [expo-location] java.lang.NullPointerException: it must not be null

Minimal reproducible example

Sadly I cannot reproduce it consistently yet…

Summary

The crash happened on Android v12, after this code which is basically similar to the doc:

async function onLocationPress() {
  const { status } = await Location.requestForegroundPermissionsAsync();

  if (status !== 'granted') {
    Alert.alert(
      t('Permission required'),
      t('You need to allow location services.'),
    );

    return;
  }

  const position = await Location.getCurrentPositionAsync({});

  // ...  
}
java.lang.NullPointerException: it must not be null
    at expo.modules.location.LocationHelpers$Companion$requestSingleLocation$1.invoke(LocationHelpers.kt:73)
    at expo.modules.location.LocationHelpers$Companion$requestSingleLocation$1.invoke(LocationHelpers.kt:72)
    at expo.modules.location.LocationHelpers$Companion.requestSingleLocation$lambda$1(LocationHelpers.kt:72)
    at expo.modules.location.LocationHelpers$Companion.$r8$lambda$W5SDDof5VIeQJZEkzL27bikXea4
    at expo.modules.location.LocationHelpers$Companion$$ExternalSyntheticLambda0.onSuccess
    at com.google.android.gms.tasks.zzm.run(com.google.android.gms:play-services-tasks@@18.0.2:1)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:233)
    at android.os.Looper.loop(Looper.java:344)
    at android.app.ActivityThread.main(ActivityThread.java:8212)
    at java.lang.reflect.Method.invoke(Method.java)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1034)

Environment

  expo-env-info 1.2.0 environment info:
    System:
      OS: macOS 14.2.1
      Shell: 3.7.0 - /opt/homebrew/bin/fish
    Binaries:
      Node: 21.6.1 - /opt/homebrew/bin/node
      Yarn: 1.22.21 - /opt/homebrew/bin/yarn
      npm: 10.2.4 - /opt/homebrew/bin/npm
    Managers:
      CocoaPods: 1.14.3 - /opt/homebrew/bin/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 23.2, iOS 17.2, macOS 14.2, tvOS 17.2, visionOS 1.0, watchOS 10.2
    IDEs:
      Android Studio: 2022.3 AI-223.8836.35.2231.11005911
      Xcode: 15.2/15C500b - /usr/bin/xcodebuild
    npmPackages:
      expo: ^50.0.2 => 50.0.2 
      react: 18.2.0 => 18.2.0 
      react-native: 0.73.2 => 0.73.2 
    npmGlobalPackages:
      eas-cli: 7.0.0
    Expo Workflow: bare

About this issue

  • Original URL
  • State: closed
  • Created 5 months ago
  • Reactions: 6
  • Comments: 22 (5 by maintainers)

Commits related to this issue

Most upvoted comments

I have access to Pixel 7 and Redmi Note, so I’ll try to reproduce it.

@Shofol If you need a fix right away you can use patch-package with changes from this PR: https://github.com/expo/expo/pull/26688

Perfect, thanks @lukmccall!

updated patch with Lukas changes for those who can’t wait for the merge/release:

Click me

expo-location+16.5.2.patch

diff --git a/node_modules/expo-location/android/src/main/java/expo/modules/location/LocationExceptions.kt b/node_modules/expo-location/android/src/main/java/expo/modules/location/LocationExceptions.kt
index c521485..757c096 100644
--- a/node_modules/expo-location/android/src/main/java/expo/modules/location/LocationExceptions.kt
+++ b/node_modules/expo-location/android/src/main/java/expo/modules/location/LocationExceptions.kt
@@ -17,6 +17,9 @@ internal class LocationRequestRejectedException(cause: Exception) :
 internal class LocationRequestCancelledException :
   CodedException("Location request has been cancelled")

+internal class CurrentLocationIsUnavailableException :
+  CodedException("Current location is unavailable. Make sure that location services are enabled")
+
 internal class LocationSettingsUnsatisfiedException :
   CodedException("Location request failed due to unsatisfied device settings")

diff --git a/node_modules/expo-location/android/src/main/java/expo/modules/location/LocationHelpers.kt b/node_modules/expo-location/android/src/main/java/expo/modules/location/LocationHelpers.kt
index a3fe07d..594a02d 100644
--- a/node_modules/expo-location/android/src/main/java/expo/modules/location/LocationHelpers.kt
+++ b/node_modules/expo-location/android/src/main/java/expo/modules/location/LocationHelpers.kt
@@ -69,8 +69,13 @@ class LocationHelpers {
     fun requestSingleLocation(locationProvider: FusedLocationProviderClient, locationRequest: CurrentLocationRequest, promise: Promise) {
       try {
         locationProvider.getCurrentLocation(locationRequest, null)
-          .addOnSuccessListener {
-            promise.resolve(LocationResponse(it))
+          .addOnSuccessListener { location: Location? ->
+            if (location == null) {
+              promise.reject(CurrentLocationIsUnavailableException())
+              return@addOnSuccessListener
+            }
+
+            promise.resolve(LocationResponse(location))
           }
           .addOnFailureListener {
             promise.reject(LocationRequestRejectedException(it))
@@ -166,7 +171,8 @@ class LocationHelpers {
     }

     fun isAnyProviderAvailable(context: Context?): Boolean {
-      val locationManager = context?.getSystemService(Context.LOCATION_SERVICE) as? LocationManager ?: return false
+      val locationManager = context?.getSystemService(Context.LOCATION_SERVICE) as? LocationManager
+        ?: return false
       return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
     }

@@ -177,7 +183,8 @@ class LocationHelpers {
           contextPermissions,
           object : Promise {
             override fun resolve(value: Any?) {
-              val result = value as? Bundle ?: throw ConversionException(Any::class.java, Bundle::class.java, "value returned by the permission promise is not a Bundle")
+              val result = value as? Bundle
+                ?: throw ConversionException(Any::class.java, Bundle::class.java, "value returned by the permission promise is not a Bundle")
               continuation.resume(PermissionRequestResponse(result))
             }

@@ -197,7 +204,8 @@ class LocationHelpers {
           contextPermissions,
           object : Promise {
             override fun resolve(value: Any?) {
-              it.resume(value as? Bundle ?: throw ConversionException(Any::class.java, Bundle::class.java, "value returned by the permission promise is not a Bundle"))
+              it.resume(value as? Bundle
+                ?: throw ConversionException(Any::class.java, Bundle::class.java, "value returned by the permission promise is not a Bundle"))
             }

             override fun reject(code: String, message: String?, cause: Throwable?) {

Thanks, @efstathiosntonas, for your help on that issue. I was able to reproduce it. Also, I’ve modified the proposed solution, and it should be merged soon.

thanks @lukmccall

Adding the devices that have the issue at least for me, I got a Samsung S22 with Android 14 and I cannot reproduce it 🤷‍♂️

Click me

Screenshot 2024-01-23 at 16 02 27