Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 715be59d90 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.
2026-05-08 03:22:15 +00:00
2 changed files with 10 additions and 8 deletions
@@ -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,
);
@@ -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;