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
- Move the block to a non-encrypted notebook if bookmark/tags are required
- Use custom-* attributes instead of bookmark/tags in encrypted notebooks
- 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
- Check notebook encryption status before using bookmark/tag features
- Use custom-* attributes for tagging in encrypted notebooks
- Hide bookmark/tag UI when the active notebook is encrypted
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
- Query asset failed [%s]
- Encrypted notebooks do not support this operation
- Do not include Markdown syntax marker [%s]
- Bookmark cannot be empty
- Encrypted notebooks do not support this operation
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/4507dbb1a30af6d8.
Report an issue: GitHub.