Skip to content

LF-5381 Guard task selectors against plan entities missing from the s…#4252

Open
kathyavini wants to merge 1 commit into
integrationfrom
LF-5381-field-details-page-crashes-when-crop-is-added-by-another-user-while-session-is-active
Open

LF-5381 Guard task selectors against plan entities missing from the s…#4252
kathyavini wants to merge 1 commit into
integrationfrom
LF-5381-field-details-page-crashes-when-crop-is-added-by-another-user-while-session-is-active

Conversation

@kathyavini

Copy link
Copy Markdown
Collaborator

Description

World class AI vs taskSlice.js 😉

I have not tested it yet and it is not urgent; the crashes in this sequence of actions (as in testing below) predated our last major release.

AI's description below:


Fixes a family of TypeError crashes in the task selectors that occur when the Redux store holds tasks whose management plan / planting management plan entities are not (yet) in the store. Observed crash sites include the location details tabs (via the Map), the tasks list, and the Crop Catalogue:

  • taskSlice.jsCannot set properties of undefined (setting 'planting_management_plan') in getManagementPlanByPlantingManagementPlan (Immer produce over an undefined management plan)
  • taskSlice.jsCannot read properties of undefined (reading 'location_id') in the plant/transplant branch of taskEntitiesSelector
  • plantTaskSlice.jsCannot destructure property 'management_plan_id' of 'plantTask.planting_management_plan' as it is undefined (Crop Catalogue); transplantTaskSlice.js has the identical latent pattern

Root cause

taskEntitiesSelector and the by-management-plan-id selectors join tasks against managementPlanSlice and plantingManagementPlanSlice without guards, assuming every referenced plan entity is loaded. That assumption cannot hold:

  • Tasks and plans arrive from independent fetches. GET /task/{farm_id} does not embed planting_management_plan in plant_task/transplant_task (it never has — the upsert in getPlantingTasksAndPlantingManagementPlansSuccessSaga receives an empty list from this endpoint), and it never populates managementPlanSlice at all. Any tasks fetch that is not preceded by a plans fetch can therefore store tasks with dangling plan references — e.g. when another user on the same farm has created a management plan since the last plans fetch.
  • Redux Persist replays such an inconsistent snapshot across reloads, so the crash survives refresh until a healing plans fetch completes before a task selector evaluates.

The crashes were reproduced with two users on one farm and confirmed in the debugger: at the moment of the throw, the crashing task referenced a planting_management_plan_id absent from plantingManagementPlanEntities. The bug predates the locations refactor release (all three ingredients date from 2021-2022; verified empirically on the pre-release production commit).

Fix

Make the task selector joins total over partial state — one rule at every cross-slice join: a task that references an entity not yet in the store joins nothing (or is dropped) and reappears when the entity loads.

  • getManagementPlanByPlantingManagementPlan returns undefined when the management plan record is missing; both call sites filter these out
  • A task whose taskType is not in the store is dropped from taskEntitiesSelector output (every consumer dereferences taskType unconditionally)
  • The plant/transplant branch tolerates a missing subtask or missing planting management plan (joins [])
  • The assignee join uses optional chaining on userFarmEntities[farm_id]
  • plantTasksByManagementPlanIdEntitiesSelector / transplantTasksByManagementPlanIdEntitiesSelector skip tasks whose plan is unresolved

Behaviour consequence: a task whose plan entities have not arrived yet is temporarily excluded from task lists instead of crashing the page; it appears as soon as the plans fetch lands — the same end state the paired fetch always produced, without the crash window.

Out of scope (possible follow-up): embedding planting_management_plan in the GET /task/{farm_id} graph to shrink the window in which a task is unresolvable.

Jira link: https://lite-farm.atlassian.net/browse/LF-5381

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

Two users on the same farm:

  1. User B logs in on a second browser; user A stays logged in.
  2. User B creates a crop management plan on a field.
  3. User A opens the field from the Map (details/tasks tabs), the tasks list, and the Crop Catalogue.
  4. Before the fix: TypeError error page, persisting across reloads. After the fix: pages render; the new plan's tasks appear once the page's own fetches complete.

Also regression-checked the fully-loaded case: tasks list, task read-only view, and Crop Catalogue with all data fetched.

Checklist:

  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • The precommit and linting ran successfully
  • I have added or updated language tags for text that's part of the UI
  • I have ordered translation keys alphabetically (optional: run pnpm i18n to help with this)
  • I have added the GNU General Public License to all new files

…tore

Tasks and management plans arrive from independent fetches, and the tasks
response embeds no planting management plans, so any tasks fetch that is not
paired with a plans fetch stores tasks whose plan entities are absent;
redux-persist then replays such snapshots across reloads. Make the task
selector joins total over partial state: drop unresolvable plan references,
skip tasks with no cached task type, and skip plant/transplant tasks whose
planting management plan has not loaded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kathyavini kathyavini self-assigned this Jul 6, 2026
@kathyavini
kathyavini requested review from a team as code owners July 6, 2026 19:19
@kathyavini
kathyavini requested review from SayakaOno and removed request for a team July 6, 2026 19:19
@kathyavini kathyavini added the bug Something isn't working label Jul 6, 2026
@kathyavini kathyavini removed their assignment Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant