grafana/grafana · error

Cannot switch layout: parent is not a LayoutParent

Error message

Cannot switch layout: parent is not a LayoutParent

What it means

Thrown by switchLayout() when the resolved path has no terminal item (resolved.item is undefined — typically the root '/' or a path resolving only to a layout manager) and that layout manager's parent is either absent or not a LayoutParent. With no LayoutParent to call switchLayout() on, the new layout cannot be installed.

Source

Thrown at public/app/features/dashboard-scene/mutation-api/commands/updateLayout.ts:128

      `Cannot convert to TabsLayout: a child's inner layout is already tabs, which would put tabs directly inside tabs.`
    );
  }
}

function switchLayout(
  resolved: ReturnType<typeof resolveLayoutPath>,
  newLayout: DashboardLayoutManager,
  path: string
): void {
  if (resolved.item) {
    if (!isLayoutParent(resolved.item)) {
      throw new Error(`Cannot switch layout: item at "${path}" is not a LayoutParent`);
    }
    resolved.item.switchLayout(newLayout);
  } else {
    const layoutParent = resolved.layoutManager.parent;
    if (!layoutParent || !isLayoutParent(layoutParent)) {
      throw new Error('Cannot switch layout: parent is not a LayoutParent');
    }
    layoutParent.switchLayout(newLayout);
  }
}

function createNewLayout(layoutType: LayoutType, currentLayout: DashboardLayoutManager): DashboardLayoutManager {
  switch (layoutType) {
    case 'RowsLayout':
      return RowsLayoutManager.createFromLayout(currentLayout);
    case 'TabsLayout':
      return TabsLayoutManager.createFromLayout(currentLayout);
    case 'GridLayout':
      return DefaultGridLayoutManager.createFromLayout(currentLayout);
    case 'AutoGridLayout':
      return AutoGridLayoutManager.createFromLayout(currentLayout);
  }
}

View on GitHub (pinned to ae3104e369)

Solutions

  1. If the dashboard supports a dedicated root-layout switch API, use that instead of UPDATE_LAYOUT at '/'.
  2. Recreate the root layout by other means (e.g. through dashboard serialization/reload) rather than converting in place.
  3. Confirm the root layout manager's parent is wired as a LayoutParent before attempting root-level conversion.
  4. Operate on a nested path where a RowItem/TabItem parent exists.
Defensive patterns

Strategy: validation

Validate before calling

// Avoid root-level ('/') conversions via UPDATE_LAYOUT when the root body has no LayoutParent parent.
// Operate at a nested path instead, or use the dashboard's dedicated root-layout API if present.
if (path === '/' && layoutType && layoutType !== currentType) {
  // do not attempt root conversion here; restructure via remove/add instead
}

Try / catch

const res = await mutation.execute({ type: 'UPDATE_LAYOUT', payload });
if (!res.success && res.error === 'Cannot switch layout: parent is not a LayoutParent') {
  // rebuild the section structurally (delete + add) instead of converting in place
}

Prevention

When it happens

Trigger: UPDATE_LAYOUT performs a same-category conversion at a path that resolves to a layout manager without an enclosing LayoutParent — most commonly the root path '/' where scene.state.body.parent is null or not a LayoutParent (updateLayout.ts:125-130).

Common situations: Trying to convert the dashboard's top-level layout type via path '/' when the root body has no LayoutParent parent; operating on a freshly constructed scene whose parent wiring is incomplete.

Related errors


AI-assisted analysis of grafana/grafana@ae3104e369 (2026-08-12). Data as JSON: /api/errors/a1bdc09a902143c0. Report an issue: GitHub.