siyuan-note/siyuan · error

invalid tabs position [%s]

Error message

invalid tabs position [%s]

What it means

When the tabs-position attribute is present on a tab container, ValidateTabsAttrs requires its trimmed value to be exactly "top" or "left". Any other string (after trimming whitespace and removing invalid control characters) is rejected with this error.

Source

Thrown at kernel/treenode/tabs.go:57

}

// 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
			}
		}
		if !found {
			return fmt.Errorf("active tab [%s] is not a direct child of [%s]", value, node.ID)
		}
	}
	return nil
}

// NormalizeTabs 修复空页和无效选中项,保留所有已有内容及块标识。

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Set the value to exactly "top" or "left" (lowercase, no extra whitespace)
  2. Validate/normalize user input in the plugin before calling setNodeAttrs
  3. Omit the attribute entirely to keep the default position

Example fix

// before
setNodeAttrs(tabsID, { "tabs-position": "Bottom" });
// after
const pos = value.trim().toLowerCase();
if (pos === "top" || pos === "left") {
  setNodeAttrs(tabsID, { "tabs-position": pos });
}
Defensive patterns

Strategy: validation

Validate before calling

const VALID = ["top", "left"];
const pos = String(value ?? "").trim().toLowerCase();
if (!VALID.includes(pos)) {
  throw new Error(`tabs-position must be "top" or "left", got ${value}`);
}

Prevention

When it happens

Trigger: Setting tabs-position on a NodeTabs node via setNodeAttrs0 with a value other than "top"/"left" — e.g. "right", "bottom", "Top", "top ". with a non-breaking space, or an empty-but-nonblank leftover string.

Common situations: Hand-written plugin config offering more orientations than supported; case-sensitivity mistakes; copying values from CSS-like configs that allow "bottom"/"right".

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/2a0adfb5712cd9c9. Report an issue: GitHub.