{"record":{"id":"a1bdc09a902143c0","repo":"grafana/grafana","slug":"cannot-switch-layout-parent-is-not-a-layoutparent","errorCode":null,"errorMessage":"Cannot switch layout: parent is not a LayoutParent","messagePattern":"Cannot switch layout: parent is not a LayoutParent","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"public/app/features/dashboard-scene/mutation-api/commands/updateLayout.ts","lineNumber":128,"sourceCode":"      `Cannot convert to TabsLayout: a child's inner layout is already tabs, which would put tabs directly inside tabs.`\n    );\n  }\n}\n\nfunction switchLayout(\n  resolved: ReturnType<typeof resolveLayoutPath>,\n  newLayout: DashboardLayoutManager,\n  path: string\n): void {\n  if (resolved.item) {\n    if (!isLayoutParent(resolved.item)) {\n      throw new Error(`Cannot switch layout: item at \"${path}\" is not a LayoutParent`);\n    }\n    resolved.item.switchLayout(newLayout);\n  } else {\n    const layoutParent = resolved.layoutManager.parent;\n    if (!layoutParent || !isLayoutParent(layoutParent)) {\n      throw new Error('Cannot switch layout: parent is not a LayoutParent');\n    }\n    layoutParent.switchLayout(newLayout);\n  }\n}\n\nfunction createNewLayout(layoutType: LayoutType, currentLayout: DashboardLayoutManager): DashboardLayoutManager {\n  switch (layoutType) {\n    case 'RowsLayout':\n      return RowsLayoutManager.createFromLayout(currentLayout);\n    case 'TabsLayout':\n      return TabsLayoutManager.createFromLayout(currentLayout);\n    case 'GridLayout':\n      return DefaultGridLayoutManager.createFromLayout(currentLayout);\n    case 'AutoGridLayout':\n      return AutoGridLayoutManager.createFromLayout(currentLayout);\n  }\n}\n","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/grafana/grafana/blob/ae3104e3690e28e72c8f0c97efc12647a70f75c3/public/app/features/dashboard-scene/mutation-api/commands/updateLayout.ts#L110-L146","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["If the dashboard supports a dedicated root-layout switch API, use that instead of UPDATE_LAYOUT at '/'.","Recreate the root layout by other means (e.g. through dashboard serialization/reload) rather than converting in place.","Confirm the root layout manager's parent is wired as a LayoutParent before attempting root-level conversion.","Operate on a nested path where a RowItem/TabItem parent exists."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Avoid root-level ('/') conversions via UPDATE_LAYOUT when the root body has no LayoutParent parent.\n// Operate at a nested path instead, or use the dashboard's dedicated root-layout API if present.\nif (path === '/' && layoutType && layoutType !== currentType) {\n  // do not attempt root conversion here; restructure via remove/add instead\n}","typeGuard":null,"tryCatchPattern":"const res = await mutation.execute({ type: 'UPDATE_LAYOUT', payload });\nif (!res.success && res.error === 'Cannot switch layout: parent is not a LayoutParent') {\n  // rebuild the section structurally (delete + add) instead of converting in place\n}","preventionTips":["Do not rely on UPDATE_LAYOUT to convert the root layout at '/' unless the root parent is a LayoutParent.","For root type changes, prefer recreating the layout through structural commands.","Confirm the layout manager's parent wiring before attempting root conversions."],"tags":["layout","mutation-api","scene-state","root","invariant"],"backgroundTag":null,"analyzedSha":"ae3104e3690e28e72c8f0c97efc12647a70f75c3","analyzedAt":"2026-08-12T12:48:38.752Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}