Skip to content

πŸ› Android: App crashes on device disconnect when using monitorCharacteristicForDevice()Β #1303

@LohenHM

Description

@LohenHM

Prerequisites

  • I checked the documentation and FAQ without finding a solution
  • I checked to make sure that this issue has not already been filed

Bug Description

When using the monitorCharacteristicForDevice() method on Android, if the peripheral device disconnects unexpectedly, the application crashes instead of propagating the disconnection error to the monitoring listener callback. The expected behavior is for the listener (error: BleError | null, characteristic: Characteristic | null) => void to be invoked with a BleError object.

The crash is caused by a java.lang.NullPointerException in the native Android code, as the Promise.reject method is called with a null error code.

Expected Behavior

The listener for monitorCharacteristicForDevice() should be called with an error object detailing the disconnection, and the app should continue running without crashing.

Current Behavior

The application crashes with a FATAL EXCEPTION. The logs indicate a java.lang.NullPointerException because Promise.reject was called with a null code parameter.

Library version

3.5.0

Device

One Plus 12, Android 15

Environment info

- React Native: v0.81
- react-native-ble-plx: v3.5.0
- Platform: Android 15

Steps to reproduce

  1. Connect to a BLE peripheral device.
  2. Start monitoring a characteristic using device.monitorCharacteristicForDevice(...).
  3. Force the device to disconnect (e.g., by turning the peripheral off or moving it out of range).
  4. Observe the application crash.

Proposed Solution / Workaround

The issue appears to be in the onError callback within the monitorCharacteristicForDevice implementation in BlePlxModule.java. The safePromise is rejected with null as the first argument.

A temporary fix is to modify the native file to provide a valid error code string.

File: /node_modules/react-native-ble-plx/android/src/main/java/com/bleplx/BlePlxModule.java

line number: 791

bleAdapter.monitorCharacteristicForDevice(
      deviceId, serviceUUID, characteristicUUID, transactionId, subscriptionType,
      new OnEventCallback<Characteristic>() {
        @Override
        public void onEvent(Characteristic data) {
          WritableArray jsResult = Arguments.createArray();
          jsResult.pushNull();
          jsResult.pushMap(characteristicConverter.toJSObject(data));
          jsResult.pushString(transactionId);
          sendEvent(Event.ReadEvent, jsResult);
        }
      }, new OnErrorCallback() {
        @Override
        public void onError(BleError error) {
-         safePromise.reject(null, errorConverter.toJs(error));
+         safePromise.reject(error.errorCode.name(), errorConverter.toJs(error));
        }
      }
    );

Relevant log output

2025-09-04 15:53:51.086 17235-733   AndroidRuntime          com.example.dev                   E  FATAL EXCEPTION: RxComputationThreadPool-3 (Ask Gemini)
                                                                                                    Process: com.example.dev, PID: 17235
                                                                                                    io.reactivex.exceptions.CompositeException: 2 exceptions occurred. 
                                                                                                    	at io.reactivex.internal.subscribers.LambdaSubscriber.onError(LambdaSubscriber.java:82)
                                                                                                    	at io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onError(FlowableDoOnEach.java:111)
                                                                                                    	at io.reactivex.internal.operators.flowable.FlowableDoOnLifecycle$SubscriptionLambdaSubscriber.onError(FlowableDoOnLifecycle.java:85)
                                                                                                    	at io.reactivex.internal.operators.flowable.FlowableObserveOn$BaseObserveOnSubscriber.checkTerminated(FlowableObserveOn.java:209)
                                                                                                    	at io.reactivex.internal.operators.flowable.FlowableObserveOn$ObserveOnSubscriber.runAsync(FlowableObserveOn.java:399)
                                                                                                    	at io.reactivex.internal.operators.flowable.FlowableObserveOn$BaseObserveOnSubscriber.run(FlowableObserveOn.java:176)
                                                                                                    	at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
                                                                                                    	at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
                                                                                                    	at java.util.concurrent.FutureTask.run(FutureTask.java:317)
                                                                                                    	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:348)
                                                                                                    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1156)
                                                                                                    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:651)
                                                                                                    	at java.lang.Thread.run(Thread.java:1119)
                                                                                                      ComposedException 1 :
                                                                                                    	com.polidea.rxandroidble2.exceptions.BleDisconnectedException: Disconnected from MAC='XX:XX:XX:XX:XX:XX' with status 8 (GATT_INSUF_AUTHORIZATION or GATT_CONN_TIMEOUT)
                                                                                                    		at com.polidea.rxandroidble2.internal.connection.RxBleGattCallback$2.onConnectionStateChange(RxBleGattCallback.java:81)
                                                                                                    		at android.bluetooth.BluetoothGatt$1$4.run(BluetoothGatt.java:390)
                                                                                                    		at android.bluetooth.BluetoothGatt.runOrQueueCallback(BluetoothGatt.java:1081)
                                                                                                    		at android.bluetooth.BluetoothGatt.-$$Nest$mrunOrQueueCallback(Unknown Source:0)
                                                                                                    		at android.bluetooth.BluetoothGatt$1.onClientConnectionState(BluetoothGatt.java:384)
                                                                                                    		at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:209)
                                                                                                    		at android.os.Binder.execTransactInternal(Binder.java:1523)
                                                                                                    		at android.os.Binder.execTransact(Binder.java:1457)
                                                                                                    	Caused by: java.lang.NullPointerException: Parameter specified as non-null is null: method com.facebook.react.bridge.PromiseImpl.reject, parameter code
                                                                                                    		at com.facebook.react.bridge.PromiseImpl.reject(Unknown Source:2)
                                                                                                    		at com.bleplx.utils.SafePromise.reject(SafePromise.java:25)
                                                                                                    		at com.bleplx.BlePlxModule$41.onError(BlePlxModule.java:791)
                                                                                                    		at com.bleplx.adapter.utils.SafeExecutor.error(SafeExecutor.java:30)
                                                                                                    		at com.bleplx.adapter.BleModule.lambda$safeMonitorCharacteristicForDevice$45(BleModule.java:1485)
                                                                                                    		at com.bleplx.adapter.BleModule.$r8$lambda$JVuqIGnSfaxzZFLoyHm91xQUhdI(Unknown Source:0)
                                                                                                    		at com.bleplx.adapter.BleModule$$ExternalSyntheticLambda3.accept(D8$$SyntheticClass:0)
                                                                                                    		at io.reactivex.internal.subscribers.LambdaSubscriber.onError(LambdaSubscriber.java:79)
                                                                                                    		at io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onError(FlowableDoOnEach.java:111)
                                                                                                    		at io.reactivex.internal.operators.flowable.FlowableDoOnLifecycle$SubscriptionLambdaSubscriber.onError(FlowableDoOnLifecycle.java:85)
                                                                                                    		at io.reactivex.internal.operators.flowable.FlowableObserveOn$BaseObserveOnSubscriber.checkTerminated(FlowableObserveOn.java:209)
                                                                                                    		at io.reactivex.internal.operators.flowable.FlowableObserveOn$ObserveOnSubscriber.runAsync(FlowableObserveOn.java:399)
                                                                                                    		at io.reactivex.internal.operators.flowable.FlowableObserveOn$BaseObserveOnSubscriber.run(FlowableObserveOn.java:176)
                                                                                                    		at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
                                                                                                    		at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
                                                                                                    		at java.util.concurrent.FutureTask.run(FutureTask.java:317)
2025-09-04 15:53:51.086 17235-733   AndroidRuntime          com.example.dev                   E  		at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:348) (Ask Gemini)
                                                                                                    		at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1156)
                                                                                                    		at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:651)
                                                                                                    		at java.lang.Thread.run(Thread.java:1119)
                                                                                                      ComposedException 2 :
                                                                                                    	java.lang.NullPointerException: Parameter specified as non-null is null: method com.facebook.react.bridge.PromiseImpl.reject, parameter code
                                                                                                    		at com.facebook.react.bridge.PromiseImpl.reject(Unknown Source:2)
                                                                                                    		at com.bleplx.utils.SafePromise.reject(SafePromise.java:25)
                                                                                                    		at com.bleplx.BlePlxModule$41.onError(BlePlxModule.java:791)
                                                                                                    		at com.bleplx.adapter.utils.SafeExecutor.error(SafeExecutor.java:30)
                                                                                                    		at com.bleplx.adapter.BleModule.lambda$safeMonitorCharacteristicForDevice$45(BleModule.java:1485)
                                                                                                    		at com.bleplx.adapter.BleModule.$r8$lambda$JVuqIGnSfaxzZFLoyHm91xQUhdI(Unknown Source:0)
                                                                                                    		at com.bleplx.adapter.BleModule$$ExternalSyntheticLambda3.accept(D8$$SyntheticClass:0)
                                                                                                    		at io.reactivex.internal.subscribers.LambdaSubscriber.onError(LambdaSubscriber.java:79)
                                                                                                    		at io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onError(FlowableDoOnEach.java:111)
                                                                                                    		at io.reactivex.internal.operators.flowable.FlowableDoOnLifecycle$SubscriptionLambdaSubscriber.onError(FlowableDoOnLifecycle.java:85)
                                                                                                    		at io.reactivex.internal.operators.flowable.FlowableObserveOn$BaseObserveOnSubscriber.checkTerminated(FlowableObserveOn.java:209)
                                                                                                    		at io.reactivex.internal.operators.flowable.FlowableObserveOn$ObserveOnSubscriber.runAsync(FlowableObserveOn.java:399)
                                                                                                    		at io.reactivex.internal.operators.flowable.FlowableObserveOn$BaseObserveOnSubscriber.run(FlowableObserveOn.java:176)
                                                                                                    		at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
                                                                                                    		at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
                                                                                                    		at java.util.concurrent.FutureTask.run(FutureTask.java:317)
                                                                                                    		at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:348)
                                                                                                    		at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1156)
                                                                                                    		at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:651)
                                                                                                    		at java.lang.Thread.run(Thread.java:1119)
2025-09-04 15:53:51.088  3181-5341  OplusAppStartupMonitor  system_server                        D  notifyUnstableAppInfo: Bundle[{unstableTime=1756981431088, reason=crash, userId=0, exceptionMsg=Parameter specified as non-null is null: method com.facebook.react.bridge.PromiseImpl.reject, parameter code, exceptionClass=java.lang.NullPointerException, app_channel_type=unstable, packageName=com.example.dev, unstable_restrict_switch=true}]
2025-09-04 15:53:51.090  3181-5676  OplusEapMa...sendEvent: system_server                        W  com.example.dev happenedcrash
2025-09-04 15:53:51.101  3181-5676  ActivityTaskManager     system_server                        W    Force finishing activity com.example.dev/com.nilesecure.MainActivity

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions