Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code d00bd2c548 fix: handle nullable navigationMenuItem.type during upgrade window
https://sonarly.com/issue/15966?type=bug

The `FindManyNavigationMenuItems` GraphQL query crashes because some `navigationMenuItem` rows have NULL `type` values, while the GraphQL schema declares `type` as non-nullable. The backfill command that populates this column was moved to the 1-20 upgrade path and hasn't been run for this v1.19.1 deployment.

Fix: Added defensive `isDefined(item.type)` checks in both `findAll` and `findById` methods of `NavigationMenuItemService`.

**Problem:** During the v1.19.1 upgrade window, the TypeORM migration adds the `type` column as nullable, and the migration that applies the NOT NULL constraint intentionally swallows failures (via savepoint rollback) when rows with NULL type exist. The backfill command that populates the `type` column was moved to the 1-20 upgrade path and doesn't run during a 1.19 upgrade. This leaves existing navigation menu items with NULL `type` values, which crash the GraphQL resolver because the `NavigationMenuItemDTO.type` field is declared non-nullable.

**Fix:** Filter out items with null `type` at the service layer before they reach GraphQL serialization. Items missing a `type` are in an incomplete/pre-backfill state and should not be returned to the client. The `as string | null` type cast is necessary because TypeScript's type system considers `type` non-nullable (matching the entity definition), but at runtime the DB column can contain NULL.

This is a minimal, safe change — affected items are simply hidden from the sidebar until the backfill command runs, which is the expected behavior for items in a transitional state.
2026-03-18 14:42:20 +00:00
@@ -54,6 +54,8 @@ export class NavigationMenuItemService {
.filter(
(item): item is NonNullable<typeof item> =>
isDefined(item) &&
// Items may have a null type before the backfill command has run
isDefined(item.type as string | null) &&
(!isDefined(item.userWorkspaceId) ||
item.userWorkspaceId === userWorkspaceId),
)
@@ -81,7 +83,10 @@ export class NavigationMenuItemService {
flatEntityMaps: flatNavigationMenuItemMaps,
});
if (!isDefined(flatNavigationMenuItem)) {
if (
!isDefined(flatNavigationMenuItem) ||
!isDefined(flatNavigationMenuItem.type as string | null)
) {
return null;
}