siyuan-note/siyuan · error

Conf.Language(313) (localized message: bookmark/tag not supp

Error message

Conf.Language(313) (localized message: bookmark/tag not supported in encrypted notebooks)

What it means

Encrypted notebooks are isolated from the global SQLite aggregation layer, so bookmark and tags attributes — which rely on that aggregation — are rejected in setNodeAttrs0. When any attribute name in the update is "bookmark" or "tags" (case-insensitive) on an encrypted box, the localized message at key 313 is returned and no attributes are written.

Source

Thrown at kernel/model/blockial.go:370

	if oldAttrs[DocSortModeAttr] != newAttrs[DocSortModeAttr] && ast.NodeDocument == node.Type {
		cache.RemoveDocIALInBox(tree.Path, tree.Box)
		cache.PutDocIALInBox(tree.Path, tree.Box, newAttrs)
	}
	pushBlockAttrs(oldAttrs, node)
	pushDocSortModeChanged(oldAttrs, node, tree)
	return
}

func setNodeAttrs0(node *ast.Node, nameValues map[string]string, boxID string) (oldAttrs map[string]string, err error) {
	if err = treenode.ValidateTabsAttrs(node, nameValues); nil != err {
		return
	}
	// 加密笔记本不支持书签和标签(依赖全局 SQLite 聚合,加密笔记本是孤岛)
	if IsEncryptedBox(boxID) && boxID != "" {
		for name := range nameValues {
			switch strings.ToLower(name) {
			case "bookmark", "tags":
				err = errors.New(Conf.Language(313))
				return
			}
		}
	}
	oldAttrs = parse.IAL2Map(node.KramdownIAL)
	newAttrsUnEsc := parse.IAL2MapUnEsc(node.KramdownIAL)
	for name := range nameValues {
		if "fold" == strings.ToLower(name) {
			delete(newAttrsUnEsc, "heading-fold")
			break
		}
	}

	for name, value := range nameValues {
		value = util.RemoveInvalidRetainCtrl(value)
		value = strings.TrimSpace(value)
		lowerName := strings.ToLower(name)
		// 转换为小写再验证属性名

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Move the block to a non-encrypted notebook if bookmark/tags are required
  2. Use custom-* attributes instead of bookmark/tags in encrypted notebooks
  3. Drop the bookmark/tags keys from the attribute payload for encrypted boxes

Example fix

// before
setNodeAttrs(boxID, id, map[string]string{"tags": "a b"}) // error: Language(313) on encrypted box
// after
if IsEncryptedBox(boxID) {
    setNodeAttrs(boxID, id, map[string]string{"custom-tags": "a b"})
} else {
    setNodeAttrs(boxID, id, map[string]string{"tags": "a b"})
}
Defensive patterns

Strategy: validation

Validate before calling

// TS: filter bookmark/tags for encrypted notebooks
const isEncrypted = window.siyuan.notebooks[notebookId]?.encrypted;
const attrs = isEncrypted
  ? Object.fromEntries(Object.entries(rawAttrs).filter(([k]) => !/^(bookmark|tags)$/i.test(k)))
  : rawAttrs;

Type guard

function safeAttrsForBox(notebookId: string, attrs: Record<string,string>): Record<string,string> {
  if (!isEncryptedBox(notebookId)) return attrs;
  const out: Record<string,string> = {};
  for (const [k, v] of Object.entries(attrs)) {
    if (!/^(bookmark|tags)$/i.test(k)) out[k] = v;
  }
  return out;
}

Prevention

When it happens

Trigger: Setting or updating the "bookmark" or "tags" attribute (any letter case) on a block inside a notebook created as encrypted (IsEncryptedBox true), via setNodeAttrs, BatchSetBlockAttrs, or any of the AV-binding paths that funnel into setNodeAttrs0.

Common situations: Users of encrypted notebooks trying to use the bookmark/tag panel; plugins that generically sync bookmark/tags across all notebooks; migration scripts assuming all notebooks support tags.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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