grafana/grafana · error
Cannot convert to TabsLayout: a child's inner layout is alre
Error message
Cannot convert to TabsLayout: a child's inner layout is already tabs, which would put tabs directly inside tabs.
What it means
Thrown by validateGroupNesting() when converting the current layout to TabsLayout while hasDirectTabsChild() reports that one of its existing children already has an inner tabs layout. Converting would place tabs directly inside tabs because the child's inner tabs would become a direct descendant of the new tabs container.
Source
Thrown at public/app/features/dashboard-scene/mutation-api/commands/updateLayout.ts:109
return [];
}
function validateGroupNesting(path: string, layoutType: LayoutType, currentLayout: DashboardLayoutManager): void {
// Rows can be nested inside both rows and tabs, and a group->group
// conversion doesn't change the nesting depth, so only tabs conversions
// need validation: tabs cannot end up directly inside tabs.
if (layoutType !== 'TabsLayout') {
return;
}
const pathParts = path === '/' ? [] : path.slice(1).split('/');
const parentSegmentType = pathParts.length >= 2 ? pathParts[pathParts.length - 2] : undefined;
if (parentSegmentType === 'tabs') {
throw new Error(`Cannot convert to TabsLayout at "${path}": tabs cannot be nested directly inside tabs.`);
}
if (hasDirectTabsChild(currentLayout)) {
throw new Error(
`Cannot convert to TabsLayout: a child's inner layout is already tabs, which would put tabs directly inside tabs.`
);
}
}
function switchLayout(
resolved: ReturnType<typeof resolveLayoutPath>,
newLayout: DashboardLayoutManager,
path: string
): void {
if (resolved.item) {
if (!isLayoutParent(resolved.item)) {
throw new Error(`Cannot switch layout: item at "${path}" is not a LayoutParent`);
}
resolved.item.switchLayout(newLayout);
} else {
const layoutParent = resolved.layoutManager.parent;
if (!layoutParent || !isLayoutParent(layoutParent)) {View on GitHub (pinned to ae3104e369)
Solutions
- First convert the inner tabs child to RowsLayout (or move it away), then convert the parent to TabsLayout.
- Convert to RowsLayout instead, which tolerates tabs children.
- Restructure so no direct child has an inner tabs layout before the parent conversion.
Example fix
// before — child already has inner tabs; parent->TabsLayout fails
mutation.execute({ type: 'UPDATE_LAYOUT', payload: { path: '/rows/0', layoutType: 'TabsLayout' } });
// after — neutralize the child's inner tabs first
mutation.execute({ type: 'UPDATE_LAYOUT', payload: { path: '/rows/0/rows/0', layoutType: 'RowsLayout' } });
mutation.execute({ type: 'UPDATE_LAYOUT', payload: { path: '/rows/0', layoutType: 'TabsLayout' } }); Defensive patterns
Strategy: validation
Validate before calling
// Before converting a layout to TabsLayout, get its structure and check no direct child has inner tabs.
const layout = await mutation.execute({ type: 'GET_LAYOUT', payload: { path } });
// If any direct child's inner layout is TabsLayout, convert that child to RowsLayout first. Try / catch
const res = await mutation.execute({ type: 'UPDATE_LAYOUT', payload });
if (!res.success && res.error?.includes("a child's inner layout is already tabs")) {
// first convert the offending child to RowsLayout, then retry the parent conversion
} Prevention
- Before converting a container to tabs, neutralize any child whose inner layout is tabs.
- Use GET_LAYOUT to inspect children before structural conversions.
- Restructure top-down: fix inner nesting before converting the parent.
When it happens
Trigger: UPDATE_LAYOUT converts a layout to TabsLayout; the layout currently contains a child (row/tab) whose own inner layout is already TabsLayout, detected by hasDirectTabsChild (updateLayout.ts:108-112).
Common situations: Flattening/restructuring an existing layout that already contains nested tabs; an LLM reorganizer that converts a rows layout (containing a tabbed child) into tabs.
Related errors
- Cannot add tabs at "${parentPath}": tabs cannot be nested di
- Cannot convert to TabsLayout at "${path}": tabs cannot be ne
- Cannot add ${addingType} at "${parentPath}": maximum nesting
- Layout nesting too deep (max 10 levels)
- Cannot convert layout: parent is not a LayoutParent
AI-assisted analysis of grafana/grafana@ae3104e369 (2026-08-12).
Data as JSON: /api/errors/3d8949cf571fd46f.
Report an issue: GitHub.