Minimal reproducible example. Two buttons issue the same createEventAsync
call; the only difference is whether recurrenceRule is present with a null
value or absent entirely.
- Button 1 —
recurrenceRule: null→ app process dies (uncaught NPE in the native module) - Button 2 — key omitted → event is created normally
npx create-expo-app@latest repro -t expo-template-blank-typescript@sdk-54
cd repro
npx expo install expo-calendar # installs 15.0.8 on SDK 54
# add the expo-calendar plugin + an android package name to app.json (see below)
# replace App.tsx with the file in this gist
npx expo prebuild --platform android --clean
npx expo run:androidapp.json additions:
{
"expo": {
"plugins": [["expo-calendar", { "calendarPermission": "Repro needs calendar access." }]],
"android": { "package": "com.example.calendarnullrepro" }
}
}The device needs at least one writable calendar. On a bare emulator there is none; create one with:
adb shell content insert \
--uri 'content://com.android.calendar/calendars?account_name=repro%40local&account_type=LOCAL&caller_is_syncadapter=true' \
--bind account_name:s:repro@local --bind account_type:s:LOCAL \
--bind name:s:ReproCal --bind calendar_displayName:s:ReproCal \
--bind calendar_access_level:i:700 --bind visible:i:1 \
--bind sync_events:i:1 --bind calendar_timezone:s:UTC \
--bind ownerAccount:s:repro@localThen grant permissions and tap button 1:
adb shell pm grant com.example.calendarnullrepro android.permission.READ_CALENDAR
adb shell pm grant com.example.calendarnullrepro android.permission.WRITE_CALENDARFATAL EXCEPTION: DefaultDispatcher-worker-2
Process: com.example.calendarnullrepro, PID: 20145
java.lang.NullPointerException: Attempt to invoke interface method
'boolean expo.modules.core.arguments.ReadableArguments.containsKey(java.lang.String)'
on a null object reference
at expo.modules.calendar.CalendarModule.saveEvent(CalendarModule.kt:483)
at expo.modules.calendar.CalendarModule.access$saveEvent(CalendarModule.kt:36)
at expo.modules.calendar.CalendarModule$definition$lambda$38$lambda$19$lambda$18$$inlined$launchAsyncWithModuleScope$1.invokeSuspend(CalendarModule.kt:252)
ActivityManager: Process com.example.calendarnullrepro (pid 20145) has died
Button 2 on the same build prints created 24 and the app stays alive.