Files
twenty/packages/twenty-server/src/engine/metadata-modules/flat-navigation-menu-item
Etienne c4a6446757 fix(navigation-menu-item): reject PAGE_LAYOUT items that don't reference a STANDALONE_PAGE layout (#22343)
## Issue

A `PAGE_LAYOUT` navigation menu item can be created pointing at a page
layout whose type is **not** `STANDALONE_PAGE` (e.g. a `DASHBOARD`). The
sidebar always links such an item to `/page/<pageLayoutId>`, but that
route only renders `STANDALONE_PAGE` layouts, anything else is
redirected to 404.
Result: a silently broken sidebar link (cc:
https://discord.com/channels/1130383047699738754/1519045990047285288).

## Root cause

- `/page/:pageLayoutId` is standalone-only by design (route guard in
`usePageChangeEffectNavigateLocation`, and `StandalonePageLayoutPage`
hardcodes `layoutType: STANDALONE_PAGE`). Dashboards/record pages are
reached elsewhere (record show page).
- A `PAGE_LAYOUT` nav item unconditionally computes
`/page/<pageLayoutId>`.
- No validation ensured the referenced layout is `STANDALONE_PAGE`: the
migration/manifest validator only checked that `pageLayoutId` was
present, the DB constraint only checked `NOT NULL`, and the runtime tool
description even suggested pinning dashboards this way. So an app
manifest pairing a `DASHBOARD` layout with a `PAGE_LAYOUT` nav item
installed cleanly and produced a dead link.

## Fix (treat as invalid config — fail fast)

- Cross-entity validation in `FlatNavigationMenuItemValidatorService`
(both create and update): when `type === PAGE_LAYOUT`, resolve the
referenced page layout from the optimistic page-layout maps and raise
`INVALID_NAVIGATION_MENU_ITEM_INPUT` if its `type !== STANDALONE_PAGE`.
Existence keeps being enforced by foreign-key resolution, so the type
check only fires when the layout resolves.
- Corrected the misleading `create_navigation_menu_item` tool
description (no longer says "e.g. a dashboard"; states the target must
be a `STANDALONE_PAGE`).
- Added unit tests covering: `STANDALONE_PAGE` accepted; `DASHBOARD`
rejected; `RECORD_PAGE` rejected; unresolved reference not flagged as a
type error.

## Files changed

- `flat-navigation-menu-item-validator.service.ts` — new
`validatePageLayoutReference` + wired into create/update.
- `create-navigation-menu-item.tool.ts` — tool description fix.
- `__tests__/flat-navigation-menu-item-validator.service.spec.ts` — new
tests (4 passing).

## Out of scope / follow-up

- To open discussion, check
https://github.com/twentyhq/twenty/pull/22255


<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22343?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-06-30 11:41:26 +02:00
..