Skip to content

null properties in maps stripped away on iOS when sent via TurboModules #52802

Closed as not planned

Description

@russellwheatley

Description

Hello - I'm a maintainer of React Native Firebase (RNFB). RNFB is currently upgrading its packages to TurboModules, and we found a discrepancy between iOS and android that was not previously an issue with NativeModules.

Here is the reproducer: https://github.com/russellwheatley/null-ios-bug

It's pretty simple; run the app on android/iOS. Press the button that appears, it will send this map to native, native will return the exact data back to the JS side:

{ data: { message: 'Hello, world!', nullType: null } }

android will faithfully return the same map, iOS will strip out the property nullType which you can see in DevTools.

This is a rather big departure from NativeModules and will cause problems for a number of RNFB packages like functions, firestore & real-time database.

This issue has been brought up before:
#49291
reactwg/react-native-releases#785

Let me know if you need any further information.

cc. @mikehardy

Steps to reproduce

  1. clone repo: https://github.com/russellwheatley/null-ios-bug
  2. run cd ReproducerApp.
  3. run yarn
  4. follow instructions in README to run app: https://github.com/russellwheatley/null-ios-bug#step-1-start-the-metro-server
  5. press button that appears, and view log in DevTools.
  6. iOS strips out property nullType because it has null value, android does not.

React Native Version

0.80.1

Affected Platforms

Runtime - iOS

Areas

TurboModule - The New Native Module System

Output of npx @react-native-community/cli info

System:
  OS: macOS 15.5
  CPU: (10) arm64 Apple M1 Max
  Memory: 127.64 MB / 32.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 22.15.0
    path: ~/.nvm/versions/node/v22.15.0/bin/node
  Yarn:
    version: 1.22.22
    path: /opt/homebrew/bin/yarn
  npm:
    version: 10.9.2
    path: ~/.nvm/versions/node/v22.15.0/bin/npm
  Watchman:
    version: 2024.12.02.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.15.2
    path: /usr/local/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 24.5
      - iOS 18.5
      - macOS 15.5
      - tvOS 18.5
      - visionOS 2.5
      - watchOS 11.5
  Android SDK:
    API Levels:
      - "26"
      - "28"
      - "29"
      - "30"
      - "31"
      - "32"
      - "33"
      - "34"
      - "35"
    Build Tools:
      - 28.0.3
      - 29.0.2
      - 29.0.3
      - 30.0.2
      - 30.0.3
      - 33.0.0
      - 33.0.1
      - 34.0.0
      - 35.0.0
    System Images:
      - android-28 | Google APIs Intel x86 Atom
      - android-28 | Google Play Intel x86 Atom
      - android-28 | Google Play Intel x86 Atom_64
      - android-29 | Intel x86 Atom_64
      - android-29 | Google APIs ARM 64 v8a
      - android-30 | Google APIs Intel x86 Atom
      - android-30 | Google Play Intel x86 Atom
      - android-32 | Google Play ARM 64 v8a
      - android-33 | Google APIs ARM 64 v8a
      - android-33 | Google APIs Intel x86 Atom_64
      - android-33 | Google Play ARM 64 v8a
      - android-33 | Google Play Intel x86 Atom_64
      - android-TiramisuPrivacySandbox | Google Play Intel x86 Atom_64
    Android NDK: 22.1.7171670
IDEs:
  Android Studio: 2024.3 AI-243.25659.59.2432.13423653
  Xcode:
    version: 16.4/16F6
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.7
    path: /usr/bin/javac
  Ruby:
    version: 2.6.10
    path: /usr/bin/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 19.0.0
    wanted: 19.0.0
  react:
    installed: 19.1.0
    wanted: 19.1.0
  react-native:
    installed: 0.80.1
    wanted: 0.80.1
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: true
  newArchEnabled: true

Stacktrace or Logs

Android log:

{ data: { message: 'Hello, world!', nullType: null } }


iOS log:

{ data: { message: 'Hello, world!' } }

MANDATORY Reproducer

https://github.com/russellwheatley/null-ios-bug

Screenshots and Videos

No response

Activity

  1. changed the title [-]map properties stripped away on iOS when sent via TurboModules[/-] [+] `null` properties in maps stripped away on iOS when sent via TurboModules[/+] on Jul 24, 2025
  2. cipolleschi commented on Jul 24, 2025

    @cipolleschi
    Contributor

    Hi @russellwheatley, thanks for the issue.
    This should be fixed in 0.81 with this commit: 4a4fd1c

    Do you mind try to create an app with npx @react-native-community/cli init MyApp --version next --skip-install which uses the RC from 0.81.0, and double check whether the problem is fixed?

  3. russellwheatley commented on Jul 25, 2025

    @russellwheatley
    Author

    Hey @cipolleschi - I copy/pasted the dependencies from running the below command into my repro:

    npx @react-native-community/cli init MyApp --version next --skip-install
    

    and it was the same result. I even cloned the repo fresh: https://github.com/russellwheatley/null-ios-bug to ensure it wasn't a stale build but it didn't make a difference.

  4. cipolleschi commented on Jul 31, 2025

    @cipolleschi
    Contributor

    @russellwheatley so, the bug was effectively addressed by this PR: #51103

    The fix is behind a feature flag, which we turned on but we had to turn off because it was causing a lot of failures internally. People and users might ended up depending on this new behavior and changing it now could be a big breaking change for our users. We need further discussions internally to understand how to roll this out.

    One of the benefits of the New Architecture and Codegen is type safety: in general, you should avoid the usage of unknown types and users should always know which are the keys involved. When this is not possible, when the users can specify custom fields, I suggest to use the Object approach that will be converted to an NSDictionary. In that way you can iterate over the keys and check for their presence.

      httpsCallable(
        name: string,
        data: Object ,
      ): Promise<{ data: ResponseData }>;
    
  5. russellwheatley commented on Aug 4, 2025

    @russellwheatley
    Author

    @cipolleschi - could you expand on that, please?

    I've tried your method of using Object but it still doesn't have the null key here: https://github.com/russellwheatley/null-ios-bug/blob/main/ReproducerApp/ios/NativeFunctionsModule/RCTNativeFunctionsModule.mm#L21

    To be super clear - I have called data.data() and looked for the null (nil key) which is not present. I'm not sure if this is what you meant when you said "iterate over the keys". See below code snippet:

    - (void)httpsCallable:(nonnull NSString *)name data:(JS::NativeFunctionsModule::SpecHttpsCallableData &)data resolve:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject { 
      	// iterate over `updatedData` or somewhere else?
    	id updatedData = data.data();
    }
  6. russellwheatley commented on Sep 2, 2025

    @russellwheatley
    Author

    @cipolleschi - anything further on this? It's a pretty big problem for RNFB, and we'll have to hack something together to keep parity between android and iOS when we migrate to TurboModules.

  7. react-native-bot commented on Mar 2, 2026

    @react-native-bot
    Collaborator

    This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

  8. added
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    on Mar 2, 2026
  9. react-native-bot commented on Mar 2, 2026

    @react-native-bot
    Collaborator

    This issue is stale because it has been open for 180 days with no activity. It will be closed in 7 days unless you comment on it or remove the "Stale" label.

  10. removed
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    on Mar 2, 2026
  11. react-native-bot commented on Aug 30, 2026

    @react-native-bot
    Collaborator

    This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

  12. added
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    on Aug 30, 2026
  13. react-native-bot commented on Sep 6, 2026

    @react-native-bot
    Collaborator

    This issue was closed because it has been stalled for 7 days with no activity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs: Triage 🔍Platform: iOSiOS applications.StaleThere has been a lack of activity on this issue and it may be closed soon.Type: New ArchitectureIssues and PRs related to new architecture (Fabric/Turbo Modules)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions