From 715be59d909cdc1abf7aff396ac6c59d70b45b64 Mon Sep 17 00:00:00 2001 From: Sonarly Claude Code Date: Fri, 8 May 2026 03:22:15 +0000 Subject: [PATCH] Missing null check on workflow.versions crashes command menu https://sonarly.com/issue/36034?type=bug When users click "Test Workflow" in the command menu, the code crashes because `getCurrentVersionId` calls `.find()` on `workflow.versions` without checking if it's null. GraphQL can return null for nested relations due to Apollo cache inconsistencies. Fix: Added null coalescing operators (`?? []`) to handle cases where `workflow.versions` is `null` in the Apollo cache. **File 1: `useWorkflowsWithCurrentVersions.ts`** - Changed `getCurrentVersionId` to first extract `const versions = workflow.versions ?? []` - Uses the safe `versions` array for both `.find()` and `.toSorted()` operations **File 2: `useWorkflowWithCurrentVersion.ts`** - Moved the null-safe `workflow?.versions ?? []` to the top of the version logic - Reused `workflowVersions` consistently for both the draft version search and sorting - Renamed the sorted copy to `sortedWorkflowVersions` for clarity This follows the same defensive pattern already used in: - Line 67 of `useWorkflowWithCurrentVersion.ts`: `[...(workflow?.versions ?? [])]` - The recent fix in commit `be4b466234` which addressed the same Apollo cache null issue in `useWorkflowVersion.ts` The root cause is that Apollo Client v4 (upgraded in #18584) has stricter normalized writes where "null always wins" in the cache. When certain GraphQL queries return `versions: null` (e.g., due to empty node selection or cache inconsistency during token renewal), the previously cached array gets overwritten with null, causing the crash. --- .../hooks/useWorkflowsWithCurrentVersions.ts | 8 ++++---- .../workflow/hooks/useWorkflowWithCurrentVersion.ts | 10 ++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/twenty-front/src/modules/command-menu-item/hooks/useWorkflowsWithCurrentVersions.ts b/packages/twenty-front/src/modules/command-menu-item/hooks/useWorkflowsWithCurrentVersions.ts index ab77ec02d4c..d9d7272ddeb 100644 --- a/packages/twenty-front/src/modules/command-menu-item/hooks/useWorkflowsWithCurrentVersions.ts +++ b/packages/twenty-front/src/modules/command-menu-item/hooks/useWorkflowsWithCurrentVersions.ts @@ -9,11 +9,11 @@ import { } from '@/workflow/types/Workflow'; const getCurrentVersionId = (workflow: Workflow): string | undefined => { - const draftVersion = workflow.versions.find( - (version) => version.status === 'DRAFT', - ); + const versions = workflow.versions ?? []; - const sortedVersions = workflow.versions.toSorted((a, b) => + const draftVersion = versions.find((version) => version.status === 'DRAFT'); + + const sortedVersions = versions.toSorted((a, b) => a.createdAt > b.createdAt ? -1 : 1, ); diff --git a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowWithCurrentVersion.ts b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowWithCurrentVersion.ts index 203d8ba032f..825ed04ba5e 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowWithCurrentVersion.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowWithCurrentVersion.ts @@ -60,15 +60,17 @@ export const useWorkflowWithCurrentVersion = ( refetchWorkflow, ]); - const draftVersion = workflow?.versions.find( + const workflowVersions = workflow?.versions ?? []; + + const draftVersion = workflowVersions.find( (workflowVersion) => workflowVersion.status === 'DRAFT', ); - const workflowVersions = [...(workflow?.versions ?? [])]; + const sortedWorkflowVersions = [...workflowVersions]; - workflowVersions.sort((a, b) => (a.createdAt > b.createdAt ? -1 : 1)); + sortedWorkflowVersions.sort((a, b) => (a.createdAt > b.createdAt ? -1 : 1)); - const latestVersion = workflowVersions[0]; + const latestVersion = sortedWorkflowVersions[0]; const currentVersionWithoutSteps = draftVersion ?? latestVersion;