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

  1. Move the documents only within the same notebook or to a notebook with the same encryption boundary
  2. Create the document in the target notebook and re-enter the content manually (content is re-encrypted at creation)
  3. 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

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


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)