siyuan-note/siyuan · error

Encrypted notebooks do not support this operation

Error message

Encrypted notebooks do not support this operation

What it means

In setNodeAttrs0 (the shared worker for SetBlockAttrs / BatchSetBlockAttrs), when the box is encrypted (IsEncryptedBox(boxID) && boxID != '') and one of the requested attribute names lower-cases to 'bookmark' or 'tags', it returns Conf.Language(313) — 'Encrypted notebooks do not support this operation'. The inline comment at blockial.go:335 states why: bookmarks and tags depend on the global SQLite aggregation, but an encrypted notebook is an isolated island, so those attributes cannot be indexed globally and are therefore rejected.

Source

Thrown at kernel/model/blockial.go:340

	if err != nil {
		return
	}

	tx.writeTree(tree)

	IncSync()
	cache.PutBlockIALInBox(node.ID, tree.Box, parse.IAL2Map(node.KramdownIAL))
	pushBlockAttrs(oldAttrs, node)
	return
}

func setNodeAttrs0(node *ast.Node, nameValues map[string]string, boxID string) (oldAttrs map[string]string, err error) {
	// 加密笔记本不支持书签和标签(依赖全局 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 251596fc0d)

Solutions

  1. Do not set 'bookmark' or 'tags' on blocks in encrypted notebooks — filter them out of the request.
  2. If tagging/bookmarking is required, move the block to a non-encrypted notebook first.
  3. In plugin/UI code, check the box encryption state (notebook conf) and disable the bookmark/tag control for encrypted boxes.

Example fix

// before
attrs := map[string]string{"bookmark": "read", "custom-x": "y"}
model.SetBlockAttrs(id, attrs)

// after: strip bookmark/tags for encrypted notebooks
boxID := treenode.GetBlockTree(id).BoxID
if model.IsEncryptedBox(boxID) {
    delete(attrs, "bookmark")
    delete(attrs, "tags")
}
model.SetBlockAttrs(id, attrs)
Defensive patterns

Strategy: validation

Validate before calling

// Strip bookmark/tags when the target block lives in an encrypted notebook.
bt := treenode.GetBlockTree(id)
if bt != nil && model.IsEncryptedBox(bt.BoxID) {
    delete(nameValues, "bookmark")
    delete(nameValues, "tags")
}

Try / catch

// HTTP caller: detect the localized 'encrypted notebooks do not support' message and skip those keys.
if (r.code === -1 && /encrypted notebook/i.test(r.msg)) {
    delete attrs.bookmark; delete attrs.tags
    r = await fetchSyncPost('/api/attr/setBlockAttrs', {id, attrs})
}

Prevention

When it happens

Trigger: POST /api/attr/setBlockAttrs or /api/attr/batchSetBlockAttrs including key 'bookmark' or 'tags' for a block that lives in an encrypted notebook. Reachable from the editor 'Bookmark'/'Add tag' affordances on such blocks.

Common situations: User encrypts a notebook then tries to bookmark or tag one of its blocks; a plugin applies the same attribute set across all notebooks regardless of encryption state; migrating a tagged doc into an encrypted box.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/32fa6a84e8998688. Report an issue: GitHub.