siyuan-note/siyuan · error
conditional replacement of encrypted attribute views is not…
Error message
conditional replacement of encrypted attribute views is not supported
What it means
Encrypted notebooks store attribute views under a box-scoped path, and the conditional (compare-and-swap) write helper util.WriteFileIfUnchanged only supports the global path scheme. When a conditional save (original != nil) targets an AV in an encrypted box (avBoxID != ""), the code refuses with this error because conditional replacement semantics are not implemented for that layout.
Solutions
- Use unconditional SaveAttributeView for attribute views in encrypted notebooks
- Detect encrypted-box AVs (avBoxID != "") and route them to the unconditional save path in your code
- If conditional replacement is required for encrypted boxes, it needs kernel support — file/track a feature request rather than bypassing the check
Example fix
// before
err = av.SaveAttributeViewIfUnchanged(attrView, original) // fails in encrypted box
// after
if boxID != "" {
err = av.SaveAttributeView(attrView)
} else {
err = av.SaveAttributeViewIfUnchanged(attrView, original)
} Defensive patterns
Strategy: fallback
Validate before calling
if boxID != "" && original != nil {
// encrypted-box AV: conditional save unsupported, plan to use SaveAttributeView
} Try / catch
if err := avlib.SaveAttributeViewIfUnchanged(attrView, original); err != nil {
if strings.Contains(err.Error(), "conditional replacement") {
err = avlib.SaveAttributeView(attrView) // unconditional save works everywhere
}
} Prevention
- Route encrypted-notebook attribute views to unconditional saves by design
- Track boxID alongside avID in automation so save strategy can be chosen up front
- Do not attempt to bypass the check by writing the file directly — that risks corrupting encrypted data
When it happens
Trigger: Calling SaveAttributeViewIfUnchanged on an attribute view that belongs to an encrypted notebook (non-empty box ID); automation doing optimistic-concurrency saves against encrypted-box databases; migration scripts using the conditional API across all AVs indiscriminately.
Common situations: Users with encrypted notebooks running plugins/scripts that use the newer conditional save API; batch jobs applying SaveAttributeViewIfUnchanged over every AV in the workspace; code paths that resolve boxID after deciding to do a conditional save.
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
- cannot remove primary key field
- Conf.Language(313)
- Conf.Language(313)
- Conf.Language(313)
- Conf.Language(386)
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/381279986c46c3d2.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/av/av.go:1041
}
restoreResolvedColors()
restoreRenderedContents()
if err != nil {
logging.LogErrorf("marshal attribute view [%s] failed: %s", av.ID, err)
return
}
// 缓存与待写入数据一致时跳过落盘;缓存未命中时再读盘比对,避免无变更的重复写入
// 通过 fallback 查找 AV 定义的实际路径(普通 box 全局,加密笔记本笔记本级)
avJSONPath, avBoxID := FindAttributeViewPath(av.ID)
if avJSONPath == "" {
// 文件不存在(首次创建),使用全局路径,boxID 为空(普通 box)
// 加密笔记本的首次创建由 handler 层通过 SetAVBoxID 预设路径
avJSONPath = GetAttributeViewDataPath(av.ID)
}
if original != nil {
if avBoxID != "" {
return errors.New("conditional replacement of encrypted attribute views is not supported")
}
if err = util.WriteFileIfUnchanged(avJSONPath, original, data); err != nil {
return err
}
cacheAttributeViewData(av, avBoxID, data)
if RichTextSpec <= av.Spec {
NotifyAttributeViewSaved(av.ID, avBoxID)
}
return nil
}
if cachedData, version, ok := cache.GetAVDataWithVersionInBox(av.ID, avBoxID); ok {
if len(cachedData) == len(data) && bytes.Equal(cachedData, data) {
cache.SetAVSearchDataInBox(av.ID, avBoxID, version, newAttributeViewSearchInfo(av))
return
}
} else {
if diskData, readErr := filelock.ReadFile(avJSONPath); nil == readErr {
// 加密笔记本的磁盘数据是密文,需先解密再比对View on GitHub (pinned to 9f775e8a12)