notifee: Android 13 BadParcelableException: Parcel android.os.Parcel: Unmarshalling unknown type code

We’ve been seeing this a reasonable amount since our app was updated to Notifee 5.5.0 (86 instances across 10 users in the last 8 days), any ideas?

It seems to be happening purely on Android 13. It’s also only happening on various models of Pixel phones but I assume that’s because it’s the only one with Android 13 available so far…

This is on React Native 0.66.3 and our top-level build.gradle contains:

buildscript {
    ext {
        buildToolsVersion = "30.0.2"
        minSdkVersion = 24
        compileSdkVersion = 31
        targetSdkVersion = 30
        ndkVersion = "21.4.7075529"
    }
    dependencies {
        // ...
        classpath("com.google.gms:google-services:4.3.10")
    }

Stack trace (it’s always the same type code and offset):

android.os.BadParcelableException: Parcel android.os.Parcel@21652a5: Unmarshalling unknown type code 1107296256 at offset 217
    at android.os.Parcel.readValue(Parcel.java:4658)
    at android.os.Parcel.readValue(Parcel.java:4490)
    at android.os.Parcel.readLazyValue(Parcel.java:4361)
    at android.os.Parcel.readArrayMap(Parcel.java:5208)
    at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:441)
    at android.os.BaseBundle.unparcel(BaseBundle.java:313)
    at android.os.BaseBundle.unparcel(BaseBundle.java:305)
    at android.os.BaseBundle.keySet(BaseBundle.java:737)
    at com.facebook.react.bridge.Arguments.fromBundle(Arguments.java:295)
    at com.facebook.react.bridge.Arguments.fromBundle(Arguments.java:312)
    at com.facebook.react.bridge.Arguments.fromBundle(Arguments.java:312)
    at io.invertase.notifee.NotifeeReactUtils.promiseResolver(NotifeeReactUtils.java:71)
    at io.invertase.notifee.NotifeeApiModule.lambda$getTriggerNotifications$5(NotifeeApiModule.java:88)
    at io.invertase.notifee.-$$Lambda$NotifeeApiModule$PNm3RTDT9NuO15y5400FmZ8sOic.onComplete
    at app.notifee.core.c.b(SourceFile:204)
    at app.notifee.core.-$$Lambda$wP11Zzh_Q5K2vywg80aCSDBhofU.onComplete
    at com.google.android.gms.tasks.zzi.run(com.google.android.gms:play-services-tasks@@18.0.1:1)
    at android.os.Handler.handleCallback(Handler.java:942)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:201)
    at android.os.Looper.loop(Looper.java:288)
    at android.app.ActivityThread.main(ActivityThread.java:7898)
    at java.lang.reflect.Method.invoke(Method.java)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 3
  • Comments: 41 (23 by maintainers)

Most upvoted comments

We got a Pixel 6a for testing the Android 12 to 13 upgrade.

Before Android 13 upgrade

  • We had 2 versions of our app installed on the device:
    • App 1
      • Equal to our production app that our users have gotten the BadParcelableException crash with
    • App 2
      • The same as App 1, but calls cancelAllNotifications on app start before calling ~getScheduledNotifications~ getTriggerNotifications
  • Both apps had local notifications scheduled before the upgrade

Results after Android 13 upgrade

  • App 1:

    • Crashed with BadParcelableException as expected
    • The crashing goes away after reinstalling the app
    • When the reinstalled app starts for the first time it immediately displays the new Android 13 notification permission dialog
    • Newly scheduled local notifications work as expected after reinstall
  • App 2:

    • Did not crash
    • Did not ask for the new Android 13 notification permission, likely because notifications were allowed on Android 12
    • Newly scheduled local notifications work as expected
    • Naturally this doesn’t test the situation where scheduled local notifications span across sessions

Our conclusion

  • Trying to call getScheduledNotifications with notifications scheduled on Android 12 causes the crash on Android 13
  • Notification objects in Android 12 and 13 look to be identical, so no idea why this happens
  • Downgrading Android from 13 back to 12 to then upgrade again to 13 doesn’t seem to be an easy feat because of the Android 13 bootloader upgrade, which means we might not be able to re-reproduce the issue with our phone
  • Our planned workaround for this issues is to check if the user has updated their phone to Android 13 and to then cancel and reschedule all notifications on app start

We’re about to do a new release - for now, we’ve removed our getTriggerNotifications call as a workaround (it was only for debug logging). We’ll at least see if we get any more instances of this error in the new build.

This is evil! Not your fault of course, just I have a hunch this is going to be really subtle. @topi-identio thanks for providing your versions, sorry it is crashing for you as well. Can you tell me what your actual version in use is (for example: cat yarn.lock | grep @notifee/react-native, as the ^ indicates to me that you could be on a higher version, all the way up to 5.7.0 so I’m not sure what if any versions are potentially removed from the set of versions to consider

Ah sorry, our version in yarn.lock is indeed 5.1.0.

Still having this issue at this date, as a workaround I have implemented a simple hook that cancel scheduled notifications when android 13 is detected for the first time on the app. Here it is in case it can help:

import {useEffect} from 'react'
import {Platform} from 'react-native'
import {cancelAllNotifications} from '~/components/notifications/notifications'
import {getStorage, setStorage} from '~/utils/storage'

const STORAGE_KEY = 'hasDeletedAllNotificationsBecauseOfAndroid13'

export const useFixAndroid13NotificationIssue = () => {
  useEffect(() => {
    if (Platform.OS === 'android' && Platform.Version >= 33) {
      const done = getStorage(STORAGE_KEY, false)
      if (!done) {
        console.log('cancel pending notifications')
        cancelAllNotifications()
        setStorage(STORAGE_KEY, true)
      }
    }
  }, [])
}

for the utility functions, I am using MMKV and a simple wrapper around notifee:

const storage = new MMKV()

export const getStorage = <T>(key: string, defaultValue: T) => {
  const value = storage.getString(key) as any
  if (value === undefined) {
    return defaultValue
  }

  return JSON.parse(value) as T
}

export const setStorage = (key: string, value: any) => {
  storage.set(key, JSON.stringify(value))
}
export const cancelAllNotifications = async () => {
  await notifee.cancelAllNotifications()
}

Tested with the database provided by @JK0N, thank you all for the investigations on this annoying issue.

@liamjones i did that already, i even tried uninstalling app and installing again than schedule notifications again no change. I will debug hope to find any error logs on debug mode.

edit: Android 13: Creating notification with custom led light blocking notification displaying

I realize I did not answer these directly:

@mikehardy I know Java but I’m not that familiar with the Android APIs - is it possible to retrieve this data from the OS without having to unmarshal it (either via Notifee or directly)? Or is the unmarshalling an automatic part of retrieval from the OS?

The unmarshal/deserialize is required to go across the react-native bridge from Java to Javascript, it is unavoidable, however it is possible at the Android code level to probe it and/or log it prior to hitting the react-native bridge. Sentry likely has ways to log things so it could be possible to do that - unknown - I know crashlytics does have ways to do it at any rate. Requires some native code, but is possible

It is so painful that this only happens on android 12 -> 13 update. The only way to reliably reproduce this will be to have a never-upgraded-to-13 phone, put trigger notifications in while it’s on 12, then update to 13 and DO NOT CANCEL THE NOTIFICATIONS OR UNINSTALL. At that point you’ve got a reliable source of bad data to probe, but if you uninstall the app or cancel the notifications they’ll go poof.

Or I suppose you could find the workmanager database in the device data and pull it out for storage, at which point you could manually copy it in at any time 🤔

Anyway, other than at the native Android level there’s no way to probe this data, and it has to be done post-data-fetch / pre-react-native-bridge

Hello Mike, I am Liam’s colleague, I was trying to reproduce this bug but unfortunately my attempts were unsuccessful, I tried the following:

  • Generated the data we believe it caused the issue on a virtual device with Android 13
  • Attempted to find a way to upgrade an Android virtual device from Android 12 to 13 but there was no way to do that
  • Attempted to go through an Android 12 virtual device app data files to copy the suspected problematic data to an Android 13 virtual device

We are considering getting a device that we can upgrade and downgrade between Android 12 and 13.

FYI we’re still trying to find a way to reproduce this with our app in an emulator based on the app configuration of users who are hitting the issue. No luck so far.

Okay, so we think we know (pending repro)

  • some kind of data in a trigger notification may cause BadParcelableException (what’s this data?)
  • on Android 13 real devices (Pixel 4a and 6 pro at least - I have a 4a so should be able to see this with a repro)
  • when getTriggerNotifications is called (it is in all the stacks…)

We need the specific data + Notifee API call to set the trigger notification followed by the getTriggerNotifications call that blows up the repro and then we can all have it under the microscope I think

We are having the same issue in production. We are currently using 5.3.0 version of the library. We tried reproducing this on an emulator but couldn’t. Everything works fine on the emulator. We are seeing a lot of crashes for Pixel users with Android 13. We are actively trying to reproduce the issue.