Skip to main content

Command Palette

Search for a command to run...

How I Fix Flagsmith's Issue #7511

Updated
2 min read

Issue Link: #7511

Sentry Issue: FLAGSMITH-FRONTEND-4N3 TypeError: Cannot read properties of null (reading 'environments') at store.getEnvironmentIdFromKey (./common/stores/project-store.js:179:34) at eMr (./web/components/CompareIdentities.tsx:63:17) ... (6 additional frame(s) were not displayed) When reading getEnvironmentIdFromKey from store, which is called in file CompareIdentities, the value is null/undefined.

Upon reading the error message, I ask myself, what variable is called in file CompareIdentities.tsx?

  const envId = ProjectStore.getEnvironmentIdFromKey(_environmentId)

I then asked, What is _environmentId? Where does it come from? Let's see getEnvironmentIdFromKey.

getEnvironment: (api_key) =>
    store.model && find(store.model.environments, { api_key }),

It's calling environments inside model variable. When does the store.model variable is null?

A model is typically null when the project data hasn't loaded yet from the API.

So my analysis question for CompareIdentities.tsx:

  1. is there a loading state check before line 63?

  2. What triggers the components to render - could it render before the project store has finished loading?

To answer number 2, I try to observe CompareIdentities component; how do ProjectStore is called?

const CompareIdentities: FC<CompareIdentitiesType> = ({
  environmentId: _environmentId,
  projectId,
}) => {
  const [leftId, setLeftId] = useState<IdentitySelectType['value']>()
  const [rightId, setRightId] = useState<IdentitySelectType['value']>()
  const envId = ProjectStore.getEnvironmentIdFromKey(_environmentId)
  const { data: projectFlags, refetch } = useGetProjectFlagsQuery(
    {
      environment: envId,
      project: projectId,
    },
    { skip: !envId || !projectId },
  )

Based on the code above, ProjectStore is called inside a render function, meaning it runs on every render, including the very first render before ProjectStore.model is loaded.

Final summary: when CompareIdentities component is rendered for the first time, it calls ProjectStore.getEnvironmentIdFromKey() -> it tries to read store.model -> store.model is still null (API hasnt responded yet) -> crash

So to solve this issue, I add guard to prevent access if store.model is null:

if (store.model) {
      const env = find(store.model.environments, { api_key })
      return env && env.id
    }

You can see my Pull Request #7778 is finally merged. Thanks a lot for Flagsmith's response. Alhamdulillah.