siyuan-note/siyuan · critical
encrypted notebook metadata verification failed after write
Error message
encrypted notebook metadata verification failed after write
What it means
After writing all encrypted state (metadata, conf, backup), the code reads the box conf back and verifies Encrypted is true and BoxCrypt is present. If the read-back does not confirm the state persisted, it raises this explicit error instead of silently treating the notebook as encrypted. It is an internal invariant check guarding against silent write failures (e.g. cache staleness or a failed save that reports success).
Solutions
- Re-run the enable-encryption operation; a transient read-back race usually resolves on retry
- Check for concurrent access: only one kernel instance should run against the workspace; stop sync clients during conversion
- Inspect data/<box>/conf.json manually — if it lacks the encrypted fields, re-attempt the conversion after fixing the storage layer
- If reproducible, report as a bug with kernel logs (this path signals an internal invariant violation)
Example fix
// before (external process restoring old conf mid-conversion) suspend Dropbox/OneDrive sync on the workspace // after retry enable-encryption with sync paused -> verification passes
Defensive patterns
Strategy: try-catch
Validate before calling
// ensure single kernel instance and no external writers before converting
const conf = await fetchGet("/api/system/version"); // kernel reachable, single instance assumed
pauseSyncClients(); Try / catch
try {
await enableNotebookEncryption(boxID, password);
} catch (e) {
if (String(e.message).includes("verification failed after write")) {
stopExternalWriters();
await enableNotebookEncryption(boxID, password); // retry once
if (stillFailing) reportBugWithKernelLogs();
}
} Prevention
- Run exactly one kernel instance per workspace
- Pause external sync/restore tools during encryption setup
- After conversion, confirm the notebook shows as encrypted in the UI before adding data
When it happens
Trigger: box.GetConf() right after SaveConf returns nil, nil, or a conf with Encrypted=false / BoxCrypt=nil — i.e. the on-disk or cached configuration does not reflect the just-written encrypted state.
Common situations: Filesystem caching or external sync restoring conf.json between write and read-back; a bug in SaveConf silently no-op; concurrent modification of conf.json by another kernel instance or process during conversion.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- 314
- 314
- attribute view rich text style entity sentinel was not…
- attribute view [ ] template plan not found
- block rowid not found after insert
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/04ed48bfcee3beab.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/crypto.go:2666
}
box := &Box{ID: id}
boxConf := box.GetConf()
boxConf.Encrypted = true
boxConf.BoxCrypt = enc
if err = encryptBoxMetadata(id, boxConf, dek); err != nil {
return "", fmt.Errorf("encrypt notebook metadata failed: %w", err)
}
if err = box.SaveConf(boxConf); err != nil {
return "", fmt.Errorf("save encrypted notebook conf failed: %w", err)
}
if err = writeNotebookCryptBackup(id, enc); err != nil {
return "", fmt.Errorf("write notebook crypt backup failed: %w", err)
}
// 回读校验加密配置已落盘,避免写失败后按普通笔记本处理
verifyConf := box.GetConf()
if verifyConf == nil || !verifyConf.Encrypted || verifyConf.BoxCrypt == nil {
err = errors.New("encrypted notebook metadata verification failed after write")
return "", err
}
markRuntimeEncryptedBox(id)
invalidateEncryptedPublishAccessCache()
// 复用刚派生的 DEK 直接开 db + 缓存,省去再次 Argon2id 解锁
cachedDEKsLock.Lock()
if err = sql.OpenEncryptedDB(id, dek); err != nil {
cachedDEKsLock.Unlock()
return "", err
}
if err = treenode.OpenEncryptedBlockTreeDB(id, dek); err != nil {
sql.CloseEncryptedDB(id)
cachedDEKsLock.Unlock()
return "", err
}
cachedDEKs[id] = dek
cachedDEKsLock.Unlock()View on GitHub (pinned to 8641553a1f)