launchdarkly / react-native-client-sdk

LaunchDarkly Client-side SDK for React Native
Other
47 stars 32 forks source link

[iOS] Thread 8: Fatal error: Unexpectedly found nil while unwrapping an Optional value #233

Closed Freire71 closed 1 year ago

Freire71 commented 1 year ago

Describe the bug After upgrading to version 8.0.0 (before I was on 7.16.0) the app crashes on startup after the build. I'm using React Native 0.71.13

To reproduce

Expected behavior The app should not crash Logs launchdarkly_react_native_client_sdk/LaunchdarklyReactNativeClient.swift:171: Fatal error: Unexpectedly found nil while unwrapping an Optional value

SDK version 8.0.0

OS/platform MacOS: 12.5 XCode: 14.0.1

Evidence

image
tanderson-ld commented 1 year ago

Thank you for reporting this issue. Could you provide a snippet of your context creation code?

louis-launchdarkly commented 1 year ago

To follow up on this @Freire71, we suspected the removal of the deprecated LDUser which we documented here is what is causing the issue, and we will look into updating the documentation to explain that better.

Zeraan commented 1 year ago

I have this problem too. Android side works fine, but iOS crashes with the above error posted. I am upgrading to latest version of React Native, 0.72.4, due to another library's version requirements, and am using those versions: "launchdarkly-react-client-sdk": "^3.0.9", "launchdarkly-react-native-client-sdk": "^8.0.0",

This is how I set my context up:

const config = {
  mobileKey: session.launchDarklyClientId,
} as LDConfig
const userContext = { kind: 'user', key: user.id, ...buildLaunchDarklyObject() }
const isInitialized = await checkIfLDClientIsInitialized()
if (!isInitialized) {
  await ldclient.configure(config, userContext)
}
if (ldclient && (isInitialized || (await checkIfLDClientIsInitialized()))) {
  flags = await ldclient.allFlags()
}

buildLaunchDarklyObject() is the custom parameters (used to be embedded as object for "custom: ") with the checkIfLDClientIsInitialized() being this:


  const checkIfLDClientIsInitialized = async (): Promise<boolean> => {
    let isInitialized = false
    await ldclient
      .isInitialized()
      .then(
        (result: boolean) => {
          isInitialized = result
        },
        (reason: any) => {
          isInitialized = false
        },
      )
      .catch(exception => {
        isInitialized = false
      })
    return isInitialized
  }
louis-launchdarkly commented 1 year ago

Hello @Zeraan, do you know which line of code that is tossing the error? Given you have the kind within the context, this looks like something different. I am also curious about the isInitialized check before calling configure, as the logic in the test app doesn't have that: https://github.com/launchdarkly/react-native-client-sdk/blob/main/ManualTestApp/App.tsx#L68

Zeraan commented 1 year ago

The error is the same as the screenshot in the original post, with the same stack trace. It looks like when I call LDClient.configure, that's when it throws that exception.

I have tried commenting out the call to check for initialization, but that didn't make any difference. From what I understood, checking isInitialized lets you know if you've got LDClient configured, preventing repeated calls in case the screen refreshes?

This is defined within a TSX element which is embedded within NavigationContainer from @react-navigation/native, like this:


        <NavigationContainer>
          <MyLDClient>
            <Stack.Navigator
              ...
            </Stack.Navigator>
          </MyLDClient>
        </NavigationContainer>
louis-launchdarkly commented 1 year ago

Hello @Zeraan, for the isInitialized part, I checked the iOS adapter code - it is handling the behavior before the configure call correctly - if there is no configure call yet, it should not crash and should return a rejected promise.

I will reach out to the engineers to get more information.

Zeraan commented 1 year ago

To clarify, it doesn't look like "isInitialized" is the part that's crashing. The callstack shows "configure" which I believe is the issue. I tried commenting out "kind: 'user'" to see if there's a difference, but it still crashes. Expanding the contextDict, it is missing "kind" in both cases NoKindProperty

louis-launchdarkly commented 1 year ago

It is weird that the kind is missing even when the input has that value. Do you know some of your code modifying that before passing into the SDK? Also, we updated https://github.com/launchdarkly/hello-react-native-typescript (still upgrading the example within this repo) to use the 8.x version of the RN SDK, can you try your context there and see does it work?

Zeraan commented 1 year ago

Weird thing is, it's now working. I put a hold on this and focused on finishing up the upgrade to RN 0.72.4. One part was updating ESLint to newer version and fixing lint errors. It pointed out one warning about "any" type in my LD client code and I made changes. I wonder if that was it. I will post my before/after codes and maybe it'll aid others.

Old code:

  const buildLaunchDarklyObject = () => {
    const userPropertiesFromDatabase = user.firebaseUserProperties || []
    const userProperties: any = {}
    userPropertiesFromDatabase.forEach((prop: any) => {
      userProperties[prop.key] = prop.value
    })

    return {
      ...userProperties,
      .
      .
      .

New code:

  const buildLaunchDarklyObject = () => {
    const userPropertiesFromDatabase = user.firebaseUserProperties || []
    const userProperties: { [key: string]: string } = {}
    userPropertiesFromDatabase.forEach((prop: UserProperty) => {
      userProperties[prop.key] = prop.value
    })

    return {
      ...userProperties,
      .
      .
      .

UserProperty is a custom class that simply have "key" and "value" string properties. I'm not sure if this was the culprit, or updating some dependencies/extra libraries, or if me deep cleaning and rebuilding everything fixed it. I will keep an eye out if this pops up again, but it does seem like there's some kind of configuration/dependency requirement that might not be explicitly stated or that we need to ensure to clear caches when updating versions or something. I could've swore that I did clean/build, many times.

louis-launchdarkly commented 1 year ago

Hello @Zeraan, thank you for reporting back and the issue is resolved for you. I hope this is only due to some cached code and will not break again for you. Please feel free to reach out to us if there is anything else.