{"record":{"id":"2e353499b43bb13f","repo":"siyuan-note/siyuan","slug":"notebook-crypto-backup-is-incomplete-or-corrupted","errorCode":null,"errorMessage":"notebook crypto backup is incomplete or corrupted","messagePattern":"notebook crypto backup is incomplete or corrupted","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/crypto.go","lineNumber":497,"sourceCode":"\n// loadNotebookCryptoBackup 从 DataDir 读取 NotebookCrypto 备份。文件不存在返回 (nil, nil)。\nfunc loadNotebookCryptoBackup() (*conf.NotebookCrypto, error) {\n\tdata, err := filelock.ReadFile(dataCryptoBackupPath())\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, err\n\t}\n\tnc := &conf.NotebookCrypto{}\n\tif err := json.Unmarshal(data, nc); err != nil {\n\t\treturn nil, err\n\t}\n\tif nc.Spec != conf.CurrentNotebookCryptoSpec {\n\t\treturn nil, fmt.Errorf(\"unsupported notebook crypto backup spec [%d]\", nc.Spec)\n\t}\n\tif !notebookCryptoConfigurationComplete(nc) {\n\t\treturn nil, errors.New(\"notebook crypto backup is incomplete or corrupted\")\n\t}\n\treturn nc, nil\n}\n\n// removeNotebookCryptoBackup 删除备份文件（禁用加密功能时调用）。文件不存在视为成功。\nfunc removeNotebookCryptoBackup() {\n\tif err := os.Remove(dataCryptoBackupPath()); err != nil && !os.IsNotExist(err) {\n\t\tlogging.LogErrorf(\"remove notebook crypto backup failed: %s\", err)\n\t}\n}\n\n// masterPasswordMigration 记录改密迁移的完整状态，用于崩溃后恢复。\ntype masterPasswordMigration struct {\n\tOldVerifier      []byte              `json:\"oldVerifier\"`\n\tNewVerifier      []byte              `json:\"newVerifier\"`\n\tNewVerifierNonce []byte              `json:\"newVerifierNonce\"`\n\tNewKDFParams     json.RawMessage     `json:\"newKDFParams\"`\n\tNewHistoryKEKs   [][]byte            `json:\"newHistoryKEKs,omitempty\"`","sourceCodeStart":479,"sourceCodeEnd":515,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/crypto.go#L479-L515","documentation":"The backup file passed the spec check but notebookCryptoConfigurationComplete reports that required crypto fields are missing. The library treats this as a corrupted or tampered backup and refuses to use it for key derivation or restore, protecting against silently restoring broken encryption state.","triggerScenarios":"loadNotebookCryptoBackup reads a backup whose Spec matches but is missing mandatory fields (empty WrappedDEK, salt, KEKMAC, etc.) — via restoreNotebookCryptoConfigFromBackup, deriveNotebookCryptoBackupCandidate, or deriveKEK.","commonSituations":"Truncated backup file after a crash, manual edits removing fields, a backup written by a buggy older build, or file corruption on disk.","solutions":["Restore the backup file from a verified copy (file-level restore or another machine's backup)","Delete the corrupt backup and re-run the master password / KEK setup to generate a fresh complete backup","Verify the backup file parses to a fully populated NotebookCrypto struct before relying on it","If recovery is impossible, use the documented master password recovery flow rather than forcing the corrupt backup"],"exampleFix":"// before: trusting a truncated backup\nnc, err := loadNotebookCryptoBackup() // incomplete\n// after: keep verified copies\nif err := verifyBackupIntegrity(backupPath); err != nil {\n    restoreFromVerifiedCopy(backupPath)\n}\nnc, err := loadNotebookCryptoBackup()","handlingStrategy":"fallback","validationCode":"var nc conf.NotebookCrypto\nif err := json.Unmarshal(raw, &nc); err != nil {\n    return fmt.Errorf(\"corrupt backup: %w\", err)\n}\nif !notebookCryptoConfigurationComplete(&nc) {\n    return fmt.Errorf(\"backup incomplete: refuse to use\")\n}","typeGuard":null,"tryCatchPattern":"nc, err := loadNotebookCryptoBackup()\nif err != nil {\n    // fall back to the documented recovery flow; never force the corrupt backup\n    if restoreErr := restoreBackupFromVerifiedCopy(); restoreErr != nil {\n        return fmt.Errorf(\"no valid backup available: %w\", restoreErr)\n    }\n    nc, err = loadNotebookCryptoBackup()\n}","preventionTips":["Keep at least two verified copies of the crypto backup","Verify backup integrity (complete config check) after every write","Take a file-level backup before upgrading or migrating the workspace","Never manually trim fields from the backup JSON"],"tags":["go","encryption","corruption","backup"],"backgroundTag":"checksum-mismatch","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}