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
- Reduce existing nesting before adding another group layer (flatten or remove a level).
- Add to an existing group of the same type at the target (the isAlreadyTargetType branch doesn't add a layer).
- Move panels into a shallower existing group instead of creating a new nested group.
- 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
- Keep dashboard layouts shallow; MAX_NESTING_DEPTH is 4 group layers.
- Adding to an existing same-type group does not consume a new layer — prefer that.
- Compute resulting depth before wrapping; flatten or move panels into shallower groups instead.
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
- Cannot add tabs at "${parentPath}": tabs cannot be nested di
- Layout nesting too deep (max 10 levels)
- Cannot convert to TabsLayout at "${path}": tabs cannot be ne
- Cannot convert to TabsLayout: a child's inner layout is alre
- Annotation '${name}' already exists
AI-assisted analysis of grafana/grafana@ae3104e369 (2026-08-12).
Data as JSON: /api/errors/eacbbc848dd0caa4.
Report an issue: GitHub.