Skip to content

fix(api): prevent crash from null member_ids on workspace modules endpoint (was mislabeled as feat) - #9541

Merged
sriramveeraghanta merged 1 commit into
previewfrom
fix/null-member-ids-workspace-modules
Aug 4, 2026
Merged

fix(api): prevent crash from null member_ids on workspace modules endpoint (was mislabeled as feat)#9541
sriramveeraghanta merged 1 commit into
previewfrom
fix/null-member-ids-workspace-modules

Conversation

@codingwolf-at

@codingwolf-at codingwolf-at commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Description

WorkspaceModulesEndpoint (GET /api/workspaces/{slug}/modules/) never annotated member_ids on its queryset, unlike the project-scoped modules endpoint which does. Since the serializer field allows null, every module returned by this endpoint serialized member_ids as null instead of [].

That null got written into the shared frontend module cache (via fetchWorkspaceModules/fetchModulesSlim, triggered on workspace-wide pages like "Your Work"). Once poisoned, opening a project's Modules view with an active "Members" filter (which persists in localStorage, so it recurs on every visit) crashed the whole page with:

TypeError: Cannot read properties of null (reading 'includes')

Fix:

  • apps/api/plane/app/views/workspace/module.py: annotate member_ids with Coalesce(ArrayAgg(...), Value([])), matching the project-scoped endpoint, so it always returns [] instead of null.
  • packages/utils/src/module.ts: defensive null-guard in shouldFilterModule (module.member_ids ?? []) so a null value can no longer crash the filter regardless of where it originates.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring
  • Performance improvements
  • Documentation update

Screenshots and Media (if applicable)

Before:

Before.mov

After:

After.mov

Test Scenarios

Reproduced live end-to-end in a local dev instance:

  1. Applied a "Members" filter on a project's Modules view (persists in localStorage).
  2. Visited a workspace-wide page ("Your Work → Assigned") to trigger fetchWorkspaceModules, poisoning the shared module cache with member_ids: null.
  3. Navigated back to the Modules tab via client-side nav — reproduced the exact crash and stack trace reported by users.
  4. Applied the fix, restarted the API, and replayed the same steps — confirmed the API now returns member_ids: [] and the page no longer crashes.

References

Reported by multiple users in Slack (CE support thread) — no linked work item.

Added an annotation to the WorkspaceModulesEndpoint to aggregate member IDs into an array, ensuring that only active members are included. This change improves the data structure returned by the API, allowing for better handling of member information in the frontend. Updated the corresponding utility function to handle potential null values for member IDs.
@codingwolf-at
codingwolf-at marked this pull request as draft August 4, 2026 11:47
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

React Doctor found no new issues. 🎉

Reviewed by React Doctor for commit f67536f.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Modules now include distinct active member IDs from the API. Utility functions use non-mutating sorting and default missing member IDs to an empty array.

Changes

Module membership handling

Layer / File(s) Summary
Module member ID annotation
apps/api/plane/app/views/workspace/module.py
The module view aggregates distinct non-deleted member UUIDs and defaults to an empty UUID array.
Module utility handling
packages/utils/src/module.ts
Module sorting no longer mutates the input array. Member filtering treats missing member_ids as an empty array.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: dheeru0198

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the null member_ids crash and the API fix, although the parenthetical note is unnecessary.
Description check ✅ Passed The description covers the bug, affected endpoints, implementation, test scenarios, screenshots, and reference information.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/null-member-ids-workspace-modules

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codingwolf-at
codingwolf-at marked this pull request as ready for review August 4, 2026 11:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/utils/src/module.ts (1)

33-34: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Redundant array copy before toSorted.

toSorted already returns a new array without mutating modules. The [...modules] spread before it creates an unneeded extra copy.

♻️ Proposed simplification
-  if (orderByKey === "name") orderedModules = [...modules].toSorted((a, b) => naturalSort(a.name, b.name));
-  if (orderByKey === "-name") orderedModules = [...modules].toSorted((a, b) => naturalSort(b.name, a.name));
+  if (orderByKey === "name") orderedModules = modules.toSorted((a, b) => naturalSort(a.name, b.name));
+  if (orderByKey === "-name") orderedModules = modules.toSorted((a, b) => naturalSort(b.name, a.name));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/utils/src/module.ts` around lines 33 - 34, Remove the redundant
spread copies in the ascending and descending name-sorting branches, calling
toSorted directly on modules while preserving the existing naturalSort
comparators and ordering behavior.
apps/api/plane/app/views/workspace/module.py (1)

115-127: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Use a single through-model path for member_ids.

members__id and modulemember__deleted_at target the same through table indirectly. Use modulemember__member_id__isnull=False, modulemember__deleted_at__isnull=True and aggregate modulemember__member_id so the active membership condition applies to the aggregated member id and join reuse remains clear.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/plane/app/views/workspace/module.py` around lines 115 - 127, Update
the `member_ids` annotation to use the single `modulemember` through-model path:
filter with `modulemember__member_id__isnull=False` and
`modulemember__deleted_at__isnull=True`, and aggregate `modulemember__member_id`
instead of `members__id`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@apps/api/plane/app/views/workspace/module.py`:
- Around line 115-127: Update the `member_ids` annotation to use the single
`modulemember` through-model path: filter with
`modulemember__member_id__isnull=False` and
`modulemember__deleted_at__isnull=True`, and aggregate `modulemember__member_id`
instead of `members__id`.

In `@packages/utils/src/module.ts`:
- Around line 33-34: Remove the redundant spread copies in the ascending and
descending name-sorting branches, calling toSorted directly on modules while
preserving the existing naturalSort comparators and ordering behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ec18e1f-6435-4fbe-927c-c8a6eaf6d644

📥 Commits

Reviewing files that changed from the base of the PR and between 1942665 and f67536f.

📒 Files selected for processing (2)
  • apps/api/plane/app/views/workspace/module.py
  • packages/utils/src/module.ts

@codingwolf-at codingwolf-at changed the title feat(api): enhance workspace module query to include member IDs fix(api): prevent crash from null member_ids on workspace modules endpoint Aug 4, 2026
@codingwolf-at codingwolf-at changed the title fix(api): prevent crash from null member_ids on workspace modules endpoint fix(api): prevent crash from null member_ids on workspace modules endpoint (was mislabeled as feat) Aug 4, 2026
@sriramveeraghanta
sriramveeraghanta merged commit a18177c into preview Aug 4, 2026
21 of 24 checks passed
@sriramveeraghanta
sriramveeraghanta deleted the fix/null-member-ids-workspace-modules branch August 4, 2026 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants