siyuan-note/siyuan · error
attribute [%s] is only supported on tab containers
Error message
attribute [%s] is only supported on tab containers
What it means
ValidateTabsAttrs enforces that the tab-specific attributes (TabsActiveIDAttr and TabsPositionAttr) are only set on nodes whose AST type is NodeTabs. Setting either attribute on any other node type — or on a nil node — aborts with this error, leaving attributes unchanged.
Source
Thrown at kernel/treenode/tabs.go:49
if nil == ret {
ret = item
}
if item.ID == activeID {
return item
}
}
return
}
// ValidateTabsAttrs 在修改属性前校验页签属性,避免部分属性已写入后才发现错误。
func ValidateTabsAttrs(node *ast.Node, attrs map[string]string) error {
for name, value := range attrs {
name = strings.ToLower(name)
if TabsActiveIDAttr != name && TabsPositionAttr != name {
continue
}
if nil == node || ast.NodeTabs != node.Type {
return fmt.Errorf("attribute [%s] is only supported on tab containers", name)
}
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
}
}View on GitHub (pinned to 8641553a1f)
Solutions
- Verify the target node type is a tab container (NodeTabs) before setting these attributes, e.g. via the block's type field
- Remove or rename the attribute if it was not intended as a tabs directive
- If the node cannot be resolved (nil), re-fetch the correct block ID first
Example fix
// before
setNodeAttrs(blockID, { "tabs-position": "left" }); // block is a paragraph
// after: only set on tab containers
const attrs = await getBlockAttrs(blockID);
if (block.type === "tabs") {
setNodeAttrs(blockID, { "tabs-position": "left" });
} Defensive patterns
Strategy: type-guard
Validate before calling
const block = await getBlockByID(blockID);
if (block.type !== "tabs" && ("tabs-position" in attrs || "tabs-active-id" in attrs)) {
throw new Error("tabs attributes require a tabs container");
} Type guard
const isTabsContainer = (b) => b.type === "tabs";
Try / catch
try {
await setNodeAttrs(blockID, attrs);
} catch (e) {
if (String(e.message).includes("only supported on tab containers")) {
console.warn("skipped tabs attr on non-tab node", blockID);
} else { throw e; }
} Prevention
- Check node type before applying tabs-prefixed attributes
- Keep tabs attributes isolated to tab-container mutation helpers
- Avoid attribute-name typos that collide with reserved tabs names
When it happens
Trigger: Calling setNodeAttrs0 (the set node attributes API) with an attribute named like the tabs active-id or tabs-position attribute on a non-tab block, or on a block whose node could not be resolved (nil).
Common situations: Plugins bulk-applying attributes without checking node type; typos in attribute names that collide with the reserved tabs attribute names; scripts written against tabs UI copying attributes onto ordinary containers.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- The attribute name can only contain lowercase English letter
- --id is required
- --attr is required (format: name=value)
- invalid attr format [%s], expected name=value
- --ids is required
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/f1f4d70156db871c.
Report an issue: GitHub.