{"record":{"id":"381279986c46c3d2","repo":"siyuan-note/siyuan","slug":"conditional-replacement-of-encrypted-attribute-views-is-not","errorCode":null,"errorMessage":"conditional replacement of encrypted attribute views is not supported","messagePattern":"conditional replacement of encrypted attribute views is not supported","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/av/av.go","lineNumber":1041,"sourceCode":"\t}\n\trestoreResolvedColors()\n\trestoreRenderedContents()\n\tif err != nil {\n\t\tlogging.LogErrorf(\"marshal attribute view [%s] failed: %s\", av.ID, err)\n\t\treturn\n\t}\n\n\t// 缓存与待写入数据一致时跳过落盘；缓存未命中时再读盘比对，避免无变更的重复写入\n\t// 通过 fallback 查找 AV 定义的实际路径（普通 box 全局，加密笔记本笔记本级）\n\tavJSONPath, avBoxID := FindAttributeViewPath(av.ID)\n\tif avJSONPath == \"\" {\n\t\t// 文件不存在（首次创建），使用全局路径，boxID 为空（普通 box）\n\t\t// 加密笔记本的首次创建由 handler 层通过 SetAVBoxID 预设路径\n\t\tavJSONPath = GetAttributeViewDataPath(av.ID)\n\t}\n\tif original != nil {\n\t\tif avBoxID != \"\" {\n\t\t\treturn errors.New(\"conditional replacement of encrypted attribute views is not supported\")\n\t\t}\n\t\tif err = util.WriteFileIfUnchanged(avJSONPath, original, data); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tcacheAttributeViewData(av, avBoxID, data)\n\t\tif RichTextSpec <= av.Spec {\n\t\t\tNotifyAttributeViewSaved(av.ID, avBoxID)\n\t\t}\n\t\treturn nil\n\t}\n\tif cachedData, version, ok := cache.GetAVDataWithVersionInBox(av.ID, avBoxID); ok {\n\t\tif len(cachedData) == len(data) && bytes.Equal(cachedData, data) {\n\t\t\tcache.SetAVSearchDataInBox(av.ID, avBoxID, version, newAttributeViewSearchInfo(av))\n\t\t\treturn\n\t\t}\n\t} else {\n\t\tif diskData, readErr := filelock.ReadFile(avJSONPath); nil == readErr {\n\t\t\t// 加密笔记本的磁盘数据是密文，需先解密再比对","sourceCodeStart":1023,"sourceCodeEnd":1059,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/av/av.go#L1023-L1059","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nerr = av.SaveAttributeViewIfUnchanged(attrView, original) // fails in encrypted box\n// after\nif boxID != \"\" {\n  err = av.SaveAttributeView(attrView)\n} else {\n  err = av.SaveAttributeViewIfUnchanged(attrView, original)\n}","handlingStrategy":"fallback","validationCode":"if boxID != \"\" && original != nil {\n  // encrypted-box AV: conditional save unsupported, plan to use SaveAttributeView\n}","typeGuard":null,"tryCatchPattern":"if err := avlib.SaveAttributeViewIfUnchanged(attrView, original); err != nil {\n  if strings.Contains(err.Error(), \"conditional replacement\") {\n    err = avlib.SaveAttributeView(attrView) // unconditional save works everywhere\n  }\n}","preventionTips":["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"],"tags":["encrypted-notebook","attribute-view","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}