grafana/grafana · error · Error

Cannot add ${addingType} at "${parentPath}": maximum nesting

Error message

Cannot add ${addingType} at "${parentPath}": maximum nesting depth (${MAX_NESTING_DEPTH} group layers) would be exceeded.

What it means

Thrown by validateNesting when wrapping the target layout in a new group (rows or tabs) would push total group nesting beyond MAX_NESTING_DEPTH (4). The check is segments.length + 1 + getGroupDepth(targetLayout), counting both ancestor segments and the wrapped subtree's own depth.

Source

Thrown at public/app/features/dashboard-scene/mutation-api/commands/layoutPathResolver.ts:195

  const isAlreadyTargetType =
    (addingType === 'rows' && targetLayout instanceof RowsLayoutManager) ||
    (addingType === 'tabs' && targetLayout instanceof TabsLayoutManager);

  // Appending an item to an existing group of the same type doesn't add a nesting layer
  if (isAlreadyTargetType) {
    return;
  }

  // The new group becomes the direct layout of the last segment's item
  if (addingType === 'tabs' && segments.length > 0 && segments[segments.length - 1].type === 'tabs') {
    throw new Error(`Cannot add tabs at "${parentPath}": tabs cannot be nested directly inside tabs.`);
  }

  // Wrapping the target layout in a new group adds one layer on top of everything nested inside it
  const resultingDepth = segments.length + 1 + getGroupDepth(targetLayout);
  if (resultingDepth > MAX_NESTING_DEPTH) {
    throw new Error(
      `Cannot add ${addingType} at "${parentPath}": maximum nesting depth (${MAX_NESTING_DEPTH} group layers) would be exceeded.`
    );
  }
}

/**
 * Resolve a path up to the parent level (one segment before the last).
 * Returns the parent layout manager and the last segment info.
 * Useful for operations that need to manipulate the parent (e.g., remove/insert).
 */
export function resolveParentPath(
  body: DashboardLayoutManager,
  path: string
): { parent: DashboardLayoutManager; segment: PathSegment } {
  const segments = parsePathSegments(path);

  if (segments.length === 0) {
    throw new Error(`Cannot resolve parent of root path "/"`);

View on GitHub (pinned to ae3104e369)

Solutions

  1. Reduce existing nesting before adding another group layer (flatten or remove a level).
  2. Add to an existing group of the same type at the target (the isAlreadyTargetType branch doesn't add a layer).
  3. Move panels into a shallower existing group instead of creating a new nested group.
  4. Re-read GET_LAYOUT to compute current depth before attempting the add.

Example fix

// before - would exceed MAX_NESTING_DEPTH (4)
await mutate('ADD_ROW', { row, parentPath: '/tabs/0/rows/0' }); // wrapping deep subtree

// after - add to an existing rows layout (same-type, no new layer)
await mutate('ADD_ROW', { row, parentPath: '/tabs/0/rows/0' }); // only if target IS already RowsLayoutManager
Defensive patterns

Strategy: validation

Validate before calling

// Compute the resulting depth before calling ADD_ROW/ADD_TAB.
import { getGroupDepth, MAX_NESTING_DEPTH } from '../../scene/layouts-shared/nestingRestrictions';
import { resolveLayoutPath, parsePathSegmentsLike } from './layoutPathResolver';

const { layoutManager } = resolveLayoutPath(scene.state.body, parentPath);
const segLen = parentPath === '/' ? 0 : parentPath.slice(1).split('/').length / 2;
const alreadySameType =
  (addingType === 'rows' && layoutManager instanceof RowsLayoutManager) ||
  (addingType === 'tabs' && layoutManager instanceof TabsLayoutManager);
if (!alreadySameType && segLen + 1 + getGroupDepth(layoutManager) > MAX_NESTING_DEPTH) {
  return { skip: true, reason: 'would exceed MAX_NESTING_DEPTH' };
}

Type guard

import { MAX_NESTING_DEPTH, getGroupDepth } from '../../scene/layouts-shared/nestingRestrictions';
function wouldExceedMaxDepth(segments: number, target: DashboardLayoutManager): boolean {
  return segments + 1 + getGroupDepth(target) > MAX_NESTING_DEPTH;
}

Try / catch

const res = await mutate(cmd, payload);
if (!res.success && /maximum nesting depth/.test(res.error)) {
  // flatten one level (remove a group) or add to an existing same-type group, then retry
}

Prevention

When it happens

Trigger: ADD_ROW or ADD_TAB at a parentPath deep enough that adding one more group layer, plus the depth of the layout being wrapped, exceeds 4. Example: wrapping a rows>tabs>rows subtree (depth 3) at path depth 2 → 2+1+3 = 6 > 4.

Common situations: Aggressive grouping of already-deep layouts; automation that wraps content repeatedly; migration that introduces extra nesting layers on top of an already-nested dashboard.

Related errors


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