Data Entry app (aggregate-data-entry v102.0.10): organisation unit tree renders blank rows with undefined props for all users

DHIS2 version: 2.41.0 (revision 614ec1c)
Data Entry app version: 102.0.10 (installed 2026-07-06, currently the latest release)
Browser: Chrome
Summary:
After manually upgrading the Data Entry app to v102.0.10 (to work around the section-filter freeze bug in the bundled 2.41.0 app), the organisation unit tree/search panel in the “Organisation unit” selector is completely empty for every user — no rows visible, nothing selectable, search returns nothing. This blocks all data entry through the UI.
Note: on this instance, “Data Entry” and “Data Entry (Beta)” now both resolve to the same installed app (/api/apps.json shows a single aggregate-data-entry entry; loading the legacy dhis-web-dataentry/index.action URL pulls its JS from dhis-web-aggregate-data-entry/assets/), so both menu shortcuts show the identical bug.
Ruled out :
• User org unit assignment — /api/me.json and the Users app both confirm organisationUnits/dataViewOrganisationUnits/teiSearchOrganisationUnits correctly include the org unit for the affected user, and the Users app’s own org unit picker renders it fine.
• Server-side org unit data — /api/organisationUnits.json and /api/organisationUnits/gist both return the org unit correctly (confirmed via direct API calls).
• Browser cache — cleared keyval-store IndexedDB and relevant localStorage keys (ouRoots, ouUsername, ouVersion), hard-reloaded. No change.
• Org unit hierarchy depth — added a temporary child org unit under the (previously childless) root to test whether a single-level hierarchy was the trigger. No change; tree stayed blank with 2 levels present.
• The app is calling the right endpoints and getting valid data back: /api/41/organisationUnits/gist?orgUnitsOffline=true&filter=level:in:[1]&filter=path:startsWith:/ and /api/41/organisationUnits?fields=path&filter=displayName:ilike: both return 200 with correct data.
Actual observed cause:
Inspecting the rendered tree via React DevTools/fiber traversal shows the tree node component IS created (data-test=“org-unit-selector-tree-node” with the expected label/checkbox/leaves structure), but every prop it receives is undefined (node, fullPath, hasChildren, checked, rootId, open, selected, etc.) — so it renders as an empty placeholder row with no visible text. This happens on every page load and is accompanied by a recurring console warning:
[re-reselect] Invalid cache key “undefined” has been returned by keySelector function.
This points to a broken memoized selector somewhere in the org unit context-selector logic that’s failing to pass the fetched org unit data down to the tree row component, despite the underlying data fetch succeeding.
Possibly relevant environment detail: this instance has an unusually small org unit hierarchy (effectively a single facility as the org unit tree root), which may be an undertested edge case for this component.
Question: has anyone else hit this on v102.0.10, and is there a known fix or workaround (e.g. reverting to a specific earlier 102.0.x, or a config flag) short of a new release?

Following up on my own thread found it, and it’s two separate bugs, both in the same function.

File: src/context-selection/org-unit-selector-bar-item/use-prefetched-organisation-units.js, function createGistPrefetchQueryArgs() this is the code path used when the utilizeGistApiForPrefetchedOrganisationUnits feature toggle is on (you can confirm it’s active for you by checking your network tab for calls to /api/{version}/organisationUnits/gist?orgUnitsOffline=true...).

Bug 1 — level is computed wrong:

js

level: path.split('/').length,

DHIS2 org unit paths always start with a leading / (e.g. /MiJ1tYcbUeF), so split('/') produces a leading empty string and the level comes out one too high, at every depth. This mismatches the offlineLevels filter computed elsewhere in the app (from the real API level field), so the tree component can never match the fetched org unit to a tree row. Every row prop comes through as undefined (check via React DevTools you’ll see node, fullPath, hasChildren, rootId etc. all undefined on the tree row). You’ll also see this console warning on every page load:

[re-reselect] Invalid cache key "undefined" has been returned by keySelector function.

Fix:

js

level: path.split('/').length - 1,

Bug 2 wrong field name (only visible after fixing bug 1):

js

results.organisationUnits.map(({ displayName, path, children }) => ({

The gist API endpoint doesn’t return a displayName field by default (unlike the regular /api/organisationUnits.json endpoint) it returns name. So even after fix #1, the tree row renders correctly positioned and clickable, but the label is permanently blank.

Fix:

js

results.organisationUnits.map(({ name: displayName, path, children }) => ({

Confirmed on v102.0.10 (2026-07-06), DHIS2 core 2.41.0. Rebuilt the app from source with both one-liners patched and it’s working now. Happy to share the patched zip if anyone wants to try it before a real fix ships.

Hi @christiano_ben

Thanks for looking into this. Could you create a bug ticket issue in https://jira.dhis2.org/ and then create a PR with your suggested fixes? You can follow the guide here: GitHub - dhis2/aggregate-data-entry-app: Data entry app for DHIS 2 · GitHub

Your PRs will be reviewed by the team. Please including a link to this topic post.

Let me know if you have any further questions. Thanks!

This is done.

I was not able to create a jira ticket.

PR #575 is open against dhis2:master: fix: render org unit tree when gist prefetch API is enabled

Okay, thanks for creating the pull request. :+1: (I recommend if you could also add tests in the code for the changes you made, it will make it quicker for the reviewer to review).

Please make sure you have an account in https://dhis2.atlassian.net/ then you will see a ‘create’ button at the top, if you select it you will be able to create a bug ticket as you can see in the screenshot:

This is helpful because it becomes part of the team’s workflow to review the ticket and check your PR.

Thanks again! :clap:

Hi @christiano_ben. Sorry that you’re having problems here and thanks for the report! Could you please check the version of your server by accessing {path/to/your/instance}/api/system/info and sharing the information for version?

I agree with your analysis that the calculation of the levels in createGistPrefetchQueryArgs seems to be incorrect. That should not be causing the issues you’re having here, though. (Thank you, of course, for the PR. We’ll be happy to merge, but I think we need to look elsewhere to fix your actual issue).

The gist api for offline organisation unit* retrieval should only be available from 2.41.9 (aggregate-data-entry-app/src/shared/feature-toggle/use-feature-toggle-context.js at master · dhis2/aggregate-data-entry-app · GitHub). Since you are using 2.41.0, this should not be triggered. Could you please check the version of your server by accessing {path/to/your/instance}/api/system/info and sharing the information for version ? This will help us see if there is something going wrong with the calculation of the version which could be leading to an incorrect query being used in the data entry app.

*It is true that api/organisationUnits/gist does not include displayName, but in the data entry app, we use a newer api/organisationUnits/gist?orgUnitsOffline=true and the inclusion of that orgUnitsOffline parameter should result in the system returning displayName.