siyuan-note/siyuan · error
Conf.Language(391)
Error message
Conf.Language(391)
What it means
MoveDocs forbids moving documents across the encryption boundary of encrypted notebooks (key 391). Encrypted notebooks each use their own data encryption key (DEK); relocating ciphertext into another notebook would encrypt/decrypt with the wrong key and corrupt data. Only moves within one notebook or between boundaries that IsSameCryptoBoundary allows are permitted.
Solutions
- Move the documents only within the same notebook or to a notebook with the same encryption boundary
- Create the document in the target notebook and re-enter the content manually (content is re-encrypted at creation)
- Temporarily export/import instead of a raw move
Example fix
// before
await fetchPost('/api/filetree/moveDocs', {fromPaths: ['/doc.sy'], toNotebook: encryptedBoxID, toPath: '/'})
// after
const srcEnc = isEncrypted(srcBoxID), dstEnc = isEncrypted(toBoxID)
if (srcEnc === dstEnc) { await fetchPost('/api/filetree/moveDocs', {fromPaths: ['/doc.sy'], toNotebook: toBoxID, toPath: '/'}) } else { /* recreate content in target */ } Defensive patterns
Strategy: validation
Validate before calling
if (srcBoxID !== toBoxID && !sameCryptoBoundary(srcBoxID, toBoxID)) throw new Error('Cross-encrypted-notebook move not allowed') Try / catch
try { await fetchPost('/api/filetree/moveDocs', args) } catch (e) { if (String(e).includes('encrypted notebook')) { /* recreate content in target instead */ } } Prevention
- Track which notebooks are encrypted and never mix them in move batches
- Recreate content in the target notebook when a boundary move is needed
- Never attempt raw file copies between encrypted and plain notebooks
When it happens
Trigger: moveDocs where fromBox.ID != toBox.ID and IsSameCryptoBoundary(fromBox.ID, toBox.ID) is false — e.g. plain notebook to encrypted notebook, encrypted A to encrypted B, or encrypted to plain.
Common situations: Bulk reorganization scripts that ignore notebook encryption status; sync setups mixing encrypted and plain notebooks; users assuming encrypted notebooks behave like normal ones.
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
- encrypted notebook document history is plaintext
- encrypted notebook has no valid key material
- imported notebook [ ] contains encrypted payload without…
- 26
- Access to encrypted notebook data is not supported via this…
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/196b84196257998b.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/file.go:1755
}
}
// 检查路径深度是否超过限制
for _, fromPath := range fromPaths {
fromBox := pathsBoxes[fromPath]
childDepth := util.GetChildDocDepth(filepath.Join(util.DataDir, fromBox.ID, fromPath))
if depth := strings.Count(toPath, "/") + childDepth; 6 < depth && !Conf.FileTree.AllowCreateDeeper {
err = errors.New(Conf.Language(118))
return
}
}
// 禁止跨加密边界移动文档:加密笔记本是孤岛,不同加密笔记本各有独立 DEK,
// 跨边界移动(普通↔加密、加密 A↔加密 B)会导致密文用错 DEK 损坏数据
for _, fromPath := range fromPaths {
fromBox := pathsBoxes[fromPath]
if fromBox.ID != toBox.ID && !IsSameCryptoBoundary(fromBox.ID, toBox.ID) {
err = errors.New(Conf.Language(391))
return
}
}
// A progress layer appears when moving more than 64 documents at once https://github.com/siyuan-note/siyuan/issues/9356
subDocsCount := 0
for _, fromPath := range fromPaths {
fromBox := pathsBoxes[fromPath]
subDocsCount += countSubDocs(fromBox.ID, fromPath)
}
needShowProgress := 64 < subDocsCount
if needShowProgress {
defer util.PushClearProgress()
}
FlushTxQueue()
luteEngine := util.NewLute()
refresh := newMoveDocsRefresh()View on GitHub (pinned to 9f775e8a12)