{"record":{"id":"aea41cc1509b24b6","repo":"grafana/grafana","slug":"parent-of-path-is-not-a-rowslayoutmanager","errorCode":null,"errorMessage":"Parent of \"${path}\" is not a RowsLayoutManager","messagePattern":"Parent of \"(.+?)\" is not a RowsLayoutManager","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"public/app/features/dashboard-scene/mutation-api/commands/removeRow.ts","lineNumber":48,"sourceCode":"    const { scene } = context;\n    enterEditModeIfNeeded(scene);\n\n    try {\n      const { path, moveContentTo } = payload;\n\n      if (moveContentTo === path) {\n        throw new Error(`moveContentTo cannot be the same path as the row being removed`);\n      }\n\n      // Resolve the row to remove\n      const resolved = resolveLayoutPath(scene.state.body, path);\n      if (!(resolved.item instanceof RowItem)) {\n        throw new Error(`Path \"${path}\" does not point to a row`);\n      }\n\n      const { parent, segment } = resolveParentPath(scene.state.body, path);\n      if (!(parent instanceof RowsLayoutManager)) {\n        throw new Error(`Parent of \"${path}\" is not a RowsLayoutManager`);\n      }\n\n      if (moveContentTo) {\n        const panels = resolved.item.state.layout.getVizPanels();\n        if (panels.length > 0) {\n          const targetResolved = resolveLayoutPath(scene.state.body, moveContentTo);\n          movePanelsToLayout(panels, targetResolved.layoutManager);\n        }\n      }\n\n      // Remove the row\n      const currentRows = [...parent.state.rows];\n      currentRows.splice(segment.index, 1);\n      parent.setState({ rows: currentRows });\n\n      return {\n        success: true,\n        data: { path },","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/grafana/grafana/blob/ae3104e3690e28e72c8f0c97efc12647a70f75c3/public/app/features/dashboard-scene/mutation-api/commands/removeRow.ts#L30-L66","documentation":"Thrown by REMOVE_ROW when resolveParentPath returns a parent that is not a RowsLayoutManager. A valid row's parent must be a RowsLayoutManager; otherwise the row's index cannot be spliced from state.rows. This guard catches scene-graph inconsistency or a path that traversed a non-rows intermediate layout.","triggerScenarios":"The path resolves to a RowItem but its computed parent is not a RowsLayoutManager, typically because a concurrent layout conversion changed the container type.","commonSituations":"Concurrent edits converted the parent from RowsLayout to TabsLayout or GridLayout between GET_LAYOUT and REMOVE_ROW; race condition in batched mutations.","solutions":["Re-fetch the layout with GET_LAYOUT to confirm the parent is still a RowsLayoutManager.","If the parent changed, the row may no longer exist in that form; move its panels individually with MOVE_PANEL before cleaning up.","Retry on a refreshed, consistent layout snapshot."],"exampleFix":"// before: parent was converted to a grid since GET_LAYOUT\nmutationApi.execute('REMOVE_ROW', { path: '/rows/0' });\n\n// after: re-fetch; if rows are gone, the panels are already at root\nconst layout = await mutationApi.execute('GET_LAYOUT', {});\n// no row to remove — layout already changed","handlingStrategy":"validation","validationCode":"// Re-fetch layout to confirm parent is RowsLayoutManager before REMOVE_ROW\nconst layout = await mutationApi.execute('GET_LAYOUT', {});\nconst node = findNodeByPath(layout.data.layout, path);\nif (!node || node.parentType !== 'RowsLayout') {\n  throw new Error('Parent is no longer a RowsLayoutManager; aborting.');\n}","typeGuard":"null","tryCatchPattern":"const res = await mutationApi.execute('REMOVE_ROW', { path, moveContentTo });\nif (!res.success && res.error.includes('not a RowsLayoutManager')) {\n  // concurrent conversion; re-fetch and move panels individually\n}","preventionTips":["Do not interleave UPDATE_LAYOUT with REMOVE_ROW.","Re-fetch GET_LAYOUT on layout-type errors.","Serialize structural mutations."],"tags":["dashboard-scene","mutation-api","layout","remove-row","concurrency"],"backgroundTag":null,"analyzedSha":"ae3104e3690e28e72c8f0c97efc12647a70f75c3","analyzedAt":"2026-08-12T12:48:38.752Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}