{"record":{"id":"e9295a158b9ee4da","repo":"grafana/grafana","slug":"path-path-does-not-point-to-a-row-e9295a","errorCode":null,"errorMessage":"Path \"${path}\" does not point to a row","messagePattern":"Path \"(.+?)\" does not point to a row","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"public/app/features/dashboard-scene/mutation-api/commands/removeRow.ts","lineNumber":43,"sourceCode":"  payloadSchema: payloads.removeRow,\n  permission: requiresNewDashboardLayouts,\n  readOnly: false,\n\n  handler: async (payload, context) => {\n    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);","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/grafana/grafana/blob/ae3104e3690e28e72c8f0c97efc12647a70f75c3/public/app/features/dashboard-scene/mutation-api/commands/removeRow.ts#L25-L61","documentation":"Thrown by REMOVE_ROW when resolveLayoutPath succeeds but the resolved .item is not a RowItem. The path must point at a row for removal; pointing it at a tab or root fails. Returned as { success: false, error }.","triggerScenarios":"Calling REMOVE_ROW with a path resolving to a TabItem (e.g. \"/tabs/0\") or the root layout. Occurs when row and tab paths are confused or the layout was restructured since the path was obtained.","commonSituations":"Stale path after an UPDATE_LAYOUT converted rows to tabs; LLM tool used a tab path for a row removal; path assembled with wrong segment type.","solutions":["Re-fetch the layout via GET_LAYOUT and use a path ending in /rows/<index>.","If the target is actually a tab, use REMOVE_TAB instead.","If the target no longer exists, treat removal as already complete."],"exampleFix":"// before: path points at a tab\nmutationApi.execute('REMOVE_ROW', { path: '/tabs/0' });\n\n// after: remove the actual tab, or re-target a row\nmutationApi.execute('REMOVE_TAB', { path: '/tabs/0' });","handlingStrategy":"validation","validationCode":"// Validate path is a row path before REMOVE_ROW\nfunction isRowPath(p) {\n  return /^\\/([a-z]+\\/\\d+)*\\/rows\\/\\d+$/.test(p);\n}\nif (!isRowPath(path)) {\n  throw new Error(`Expected a row path ending in /rows/<index>, got: ${path}`);\n}","typeGuard":"null","tryCatchPattern":"const res = await mutationApi.execute('REMOVE_ROW', { path, moveContentTo });\nif (!res.success && res.error.includes('does not point to a row')) {\n  if (path.includes('/tabs/')) {\n    await mutationApi.execute('REMOVE_TAB', { path });\n  }\n}","preventionTips":["Use GET_LAYOUT to obtain valid row paths.","Ensure the path's terminal segment is 'rows' for REMOVE_ROW.","If the target is a tab, use REMOVE_TAB instead."],"tags":["dashboard-scene","mutation-api","layout","remove-row","path-validation"],"backgroundTag":null,"analyzedSha":"ae3104e3690e28e72c8f0c97efc12647a70f75c3","analyzedAt":"2026-08-12T12:48:38.752Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}