grafana/grafana · error · Error

Path "${path}" does not point to a row

Error message

Path "${path}" does not point to a row

What it means

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 }.

Source

Thrown at public/app/features/dashboard-scene/mutation-api/commands/removeRow.ts:43

  payloadSchema: payloads.removeRow,
  permission: requiresNewDashboardLayouts,
  readOnly: false,

  handler: async (payload, context) => {
    const { scene } = context;
    enterEditModeIfNeeded(scene);

    try {
      const { path, moveContentTo } = payload;

      if (moveContentTo === path) {
        throw new Error(`moveContentTo cannot be the same path as the row being removed`);
      }

      // Resolve the row to remove
      const resolved = resolveLayoutPath(scene.state.body, path);
      if (!(resolved.item instanceof RowItem)) {
        throw new Error(`Path "${path}" does not point to a row`);
      }

      const { parent, segment } = resolveParentPath(scene.state.body, path);
      if (!(parent instanceof RowsLayoutManager)) {
        throw new Error(`Parent of "${path}" is not a RowsLayoutManager`);
      }

      if (moveContentTo) {
        const panels = resolved.item.state.layout.getVizPanels();
        if (panels.length > 0) {
          const targetResolved = resolveLayoutPath(scene.state.body, moveContentTo);
          movePanelsToLayout(panels, targetResolved.layoutManager);
        }
      }

      // Remove the row
      const currentRows = [...parent.state.rows];
      currentRows.splice(segment.index, 1);

View on GitHub (pinned to ae3104e369)

Solutions

  1. Re-fetch the layout via GET_LAYOUT and use a path ending in /rows/<index>.
  2. If the target is actually a tab, use REMOVE_TAB instead.
  3. If the target no longer exists, treat removal as already complete.

Example fix

// before: path points at a tab
mutationApi.execute('REMOVE_ROW', { path: '/tabs/0' });

// after: remove the actual tab, or re-target a row
mutationApi.execute('REMOVE_TAB', { path: '/tabs/0' });
Defensive patterns

Strategy: validation

Validate before calling

// Validate path is a row path before REMOVE_ROW
function isRowPath(p) {
  return /^\/([a-z]+\/\d+)*\/rows\/\d+$/.test(p);
}
if (!isRowPath(path)) {
  throw new Error(`Expected a row path ending in /rows/<index>, got: ${path}`);
}

Type guard

null

Try / catch

const res = await mutationApi.execute('REMOVE_ROW', { path, moveContentTo });
if (!res.success && res.error.includes('does not point to a row')) {
  if (path.includes('/tabs/')) {
    await mutationApi.execute('REMOVE_TAB', { path });
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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