siyuan-note/siyuan · error
encrypted notebook key envelope nonce mismatch
Error message
encrypted notebook key envelope nonce mismatch
What it means
Thrown by validateWrappedDEKEnvelope when the nonce embedded inside the WrappedDEK ciphertext envelope does not match the separately stored WrapNonce field. This is an integrity/consistency check: the WrapNonce is recorded at wrap time and must match the nonce in the ciphertext. A mismatch indicates the two fields were independently modified or come from different encryption operations.
Source
Thrown at kernel/model/crypto.go:1622
if err := validateWrappedDEKEnvelope(enc); err != nil {
return nil, err
}
return util.DecryptWithAAD(kek, enc.WrappedDEK, wrappedDEKAAD(boxID))
}
func validateWrappedDEKEnvelope(enc *conf.BoxEncryption) error {
if enc == nil || enc.Spec != boxEncryptionSpec {
return errors.New("unsupported encrypted notebook key envelope")
}
if enc.CreatedAt <= 0 {
return errors.New("encrypted notebook key envelope creation time is missing")
}
nonce, err := util.EncryptionNonce(enc.WrappedDEK)
if err != nil {
return fmt.Errorf("invalid encrypted notebook key envelope: %w", err)
}
if !bytes.Equal(nonce, enc.WrapNonce) {
return errors.New("encrypted notebook key envelope nonce mismatch")
}
return nil
}
func validateBoxEncryption(enc *conf.BoxEncryption) error {
if err := validateWrappedDEKEnvelope(enc); err != nil {
return err
}
if _, err := util.EncryptionNonce(enc.Metadata); err != nil {
return fmt.Errorf("invalid encrypted notebook metadata envelope: %w", err)
}
return nil
}
// mustEncryptionNonce 从刚刚成功生成的密文中提取 nonce。生成密文格式错误属于内部不变量被破坏,直接终止执行。
func mustEncryptionNonce(ciphertext []byte) []byte {
nonce, err := util.EncryptionNonce(ciphertext)
if err != nil {View on GitHub (pinned to 251596fc0d)
Solutions
- Restore both WrappedDEK and WrapNonce from the same source (conf backup or per-notebook crypt backup) so they're consistent.
- If a master-password migration is pending, restart SiYuan to let recoverMasterPasswordMigration re-write both fields atomically.
- Force a full sync of the notebook's conf.json from a device where the pair is consistent.
Defensive patterns
Strategy: validation
Validate before calling
// Check nonce consistency before unlocking:
nonce, err := util.EncryptionNonce(boxCrypt.WrappedDEK)
if err == nil && !bytes.Equal(nonce, boxCrypt.WrapNonce) {
// nonce mismatch — conf is internally inconsistent, restore from backup
} Prevention
- Always update WrappedDEK and WrapNonce together — they're produced by the same EncryptWithAAD call.
- Resolve sync conflicts by taking the entire BoxCrypt struct from one source, not mixing fields.
- Keep per-notebook backups so a consistent pair can be restored.
When it happens
Trigger: Fires during validateWrappedDEKEnvelope (reached from decryptWrappedDEK during unlock or ChangeMasterPassword). Concretely: util.EncryptionNonce(WrappedDEK) succeeds and returns a nonce, but bytes.Equal(nonce, enc.WrapNonce) is false.
Common situations: A sync conflict merged a WrappedDEK from one device with a WrapNonce from another. Manual editing of either field. A partial master-password migration updated WrappedDEK but not WrapNonce (or vice versa). Copy-paste errors when moving config between notebooks.
Related errors
- path belongs to encrypted notebook [%s]: %s
- encrypted .sy [%s]: base id [%s] != root id [%s]
- 316
- unsupported encrypted notebook key envelope
- encrypted notebook key envelope creation time is missing
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/1225675c6c6405ea.
Report an issue: GitHub.