siyuan-note/siyuan · error
invalid historical notebook encryption key
Error message
invalid historical notebook encryption key
What it means
During decryption of historical key-encryption-keys (KEKs), a KEK successfully authenticated via AAD but the resulting plaintext key was not exactly 32 bytes. This indicates the stored wrapped history key blob is malformed or was produced by an incompatible format, so the derived historical key is rejected instead of being used.
Source
Thrown at kernel/model/crypto_history_keys.go:44
const historyKEKAAD = "siyuan:history-kek:v1"
// decryptHistoryKEKs 只在当前配置已经完成主密码认证后使用,返回值由调用方在使用结束时清零。
func decryptHistoryKEKs(kek []byte, wrappedKeys [][]byte) (keys [][]byte, err error) {
defer func() {
if err != nil {
clearHistoryKEKs(keys)
keys = nil
}
}()
for _, wrapped := range wrappedKeys {
key, decryptErr := util.DecryptWithAAD(kek, wrapped, []byte(historyKEKAAD))
if decryptErr != nil {
return keys, decryptErr
}
if len(key) != 32 {
zeroAndClear(key)
return keys, errors.New("invalid historical notebook encryption key")
}
keys = append(keys, key)
}
return keys, nil
}
func clearHistoryKEKs(keys [][]byte) {
for _, key := range keys {
zeroAndClear(key)
}
}
// rewrapHistoryKEKs 将历次 KEK 和本次旧 KEK 一起封装到新 KEK 下,恢复不依赖历史所在设备。
func rewrapHistoryKEKs(oldKEK, newKEK []byte, wrappedKeys [][]byte) (ret [][]byte, err error) {
keys, err := decryptHistoryKEKs(oldKEK, wrappedKeys)
if err != nil {
return nil, err
}View on GitHub (pinned to 8641553a1f)
Solutions
- Restore the affected encrypted notebook's key/metadata files from a known-good backup or sync snapshot.
- Verify the master password is correct — a wrong password should fail AAD authentication before this check, so if you get here the blob itself is likely truncated.
- Re-wrap history keys by re-entering the master password through the official migration flow rather than editing key files manually.
- If reproducible, report it as data corruption; the 32-byte length invariant must always hold for valid envelopes.
Defensive patterns
Strategy: fallback
Try / catch
keys, err := decryptHistoryKEKs(masterKey, wrappedList)
if err != nil {
return fmt.Errorf("history keys unusable, restore from backup: %w", err)
} Prevention
- Never hand-edit key envelope files; use the official password migration flow.
- Keep backups/sync snapshots of the workspace including key metadata.
- After restoring from old backups, verify history key access before deleting anything.
When it happens
Trigger: decryptHistoryKEKs decrypts a wrapped history KEK with util.DecryptWithAAD and the decrypted length differs from 32 bytes; reached via deriveKEK, rewrapHistoryKEKs, decryptWrappedDEKWithHistory, or the history-key tests.
Common situations: Hand-edited or partially truncated key envelope files; data restored from an old backup produced by an earlier envelope format; corruption during sync merging key metadata.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- check encrypted notebook history failed: %w
- encrypted document history root ID does not match its filena
- encrypted attribute view history is missing notebook context
- master password migration is pending
- Please unlock the encrypted notebook first
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/ec69951a0c43006e.
Report an issue: GitHub.