siyuan-note/siyuan · error
active tab [%s] is not a direct child of [%s]
Error message
active tab [%s] is not a direct child of [%s]
What it means
When the tabs active-id attribute is set on a tab container, ValidateTabsAttrs walks the node's direct children looking for a NodeTabItem whose ID equals the given value. If no direct child matches, the attribute would point at a tab that is not an immediate child, so the update is rejected.
Source
Thrown at kernel/treenode/tabs.go:69
value = strings.TrimSpace(util.RemoveInvalidRetainCtrl(value))
if "" == value {
continue
}
if TabsPositionAttr == name {
if "top" != value && "left" != value {
return fmt.Errorf("invalid tabs position [%s]", value)
}
continue
}
found := false
for item := node.FirstChild; nil != item; item = item.Next {
if ast.NodeTabItem == item.Type && item.ID == value {
found = true
break
}
}
if !found {
return fmt.Errorf("active tab [%s] is not a direct child of [%s]", value, node.ID)
}
}
return nil
}
// NormalizeTabs 修复空页和无效选中项,保留所有已有内容及块标识。
func NormalizeTabs(root *ast.Node) (changed bool) {
if nil == root {
return
}
ast.Walk(root, func(node *ast.Node, entering bool) ast.WalkStatus {
if entering {
return ast.WalkContinue
}
if ast.NodeTabItem == node.Type {
if !hasContentChild(node) {
node.AppendChild(NewParagraph(""))
changed = trueView on GitHub (pinned to 8641553a1f)
Solutions
- Use the ID of a direct NodeTabItem child of the tabs container (not the content block inside it)
- Re-read the tabs container's children to get current, valid tab IDs before setting the attribute
- Remove the attribute or let NormalizeTabs repair the invalid selection if the tab was deleted
Example fix
// before
setNodeAttrs(tabsID, { "tabs-active-id": someDeepBlockID });
// after: pick an actual direct child tab item
const tabItemID = directChildTabItems(tabsID)[0].id;
setNodeAttrs(tabsID, { "tabs-active-id": tabItemID }); Defensive patterns
Strategy: validation
Validate before calling
const tabsNode = await getBlockByID(tabsID);
const childIDs = await getChildBlockIDs(tabsID); // direct children only
if (!childIDs.includes(activeTabID)) {
throw new Error(`${activeTabID} is not a direct child of ${tabsID}`);
} Prevention
- Re-read tab item IDs from the live tree; never cache them across edits
- Distinguish tab item IDs from the content block IDs inside each tab
- Let NormalizeTabs repair invalid selections after deletions
When it happens
Trigger: Setting the tabs active-id attribute via setNodeAttrs0 to an ID that is not a direct NodeTabItem child of the target tabs node — e.g. a nested block inside a tab panel, a tab from another tabs container, or a stale/deleted tab ID.
Common situations: Plugins caching tab IDs that were later deleted or moved; confusing the content block inside a tab with the tab item itself; referencing tabs from a different container after refactoring.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- attribute [%s] is only supported on tab containers
- invalid tabs position [%s]
- data?.msg || data?.message || window.siyuan.languages._kerne
- wrong layout type
- filter nesting depth exceeds the maximum allowed
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/6a0385f11c45057d.
Report an issue: GitHub.