{"record":{"id":"b5f564c669e27959","repo":"siyuan-note/siyuan","slug":"master-password-migration-is-pending-master-passw-b5f564","errorCode":null,"errorMessage":"master password migration is pending: Master password change partially failed. Please restart SiYuan to complete recovery. Detail: %s: update notebook crypt backup failed: %s","messagePattern":"master password migration is pending: Master password change partially failed\\. Please restart SiYuan to complete recovery\\. Detail: (.+?): update notebook crypt backup failed: (.+?)","errorType":"exception","errorClass":"errMasterPasswordMigrationPending","httpStatus":null,"severity":"critical","filePath":"kernel/model/crypto.go","lineNumber":1814,"sourceCode":"\t\t\t\t\tMetadata:   entry.Metadata,\n\t\t\t\t\tCreatedAt:  time.Now().UnixMilli(),\n\t\t\t\t}\n\t\t\t\tif saveErr := box.SaveConf(boxConf); saveErr != nil {\n\t\t\t\t\treturn fmt.Errorf(\"%w: %s\", errMasterPasswordMigrationPending,\n\t\t\t\t\t\tfmt.Sprintf(Conf.Language(320), entry.BoxID+\": rebuild encrypted conf from migration entry failed: \"+saveErr.Error()))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tboxConf.BoxCrypt.WrappedDEK = entry.NewWrappedDEK\n\t\tboxConf.BoxCrypt.Spec = entry.NewSpec\n\t\tboxConf.BoxCrypt.WrapNonce = entry.NewWrapNonce\n\t\tboxConf.BoxCrypt.Metadata = append([]byte(nil), entry.Metadata...)\n\t\tif err = box.SaveConf(boxConf); err != nil {\n\t\t\treturn fmt.Errorf(\"%w: %s\", errMasterPasswordMigrationPending,\n\t\t\t\tfmt.Sprintf(Conf.Language(320), entry.BoxID+\": save conf failed: \"+err.Error()))\n\t\t}\n\t\tif err = writeNotebookCryptBackup(entry.BoxID, boxConf.BoxCrypt); err != nil {\n\t\t\treturn fmt.Errorf(\"%w: %s\", errMasterPasswordMigrationPending,\n\t\t\t\tfmt.Sprintf(Conf.Language(320), entry.BoxID+\": update notebook crypt backup failed: \"+err.Error()))\n\t\t}\n\t}\n\n\t// Phase 4: 先持久化全局备份，再清除 manifest，确保崩溃后可恢复\n\tif err = saveNotebookCryptoBackup(newKEK); err != nil {\n\t\treturn fmt.Errorf(\"%w: %s\", errMasterPasswordMigrationPending,\n\t\t\tfmt.Sprintf(Conf.Language(320), \"save notebook crypto backup failed: \"+err.Error()))\n\t}\n\tremoveMasterPasswordMigration()\n\tIncSync()\n\treturn nil\n}\n\n// IsEncryptedBox 判断给定 boxID 是否为加密笔记本。\n// 配置缺失或损坏时依次检查运行时身份、独立备份和密文标识，任何检查错误都按加密笔记本处理。\nfunc IsEncryptedBox(boxID string) bool {\n\tif !ast.IsNodeIDPattern(boxID) {","sourceCodeStart":1796,"sourceCodeEnd":1832,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/model/crypto.go#L1796-L1832","documentation":"Returned by ChangeMasterPassword Phase 3 (crypto.go:1813-1816) when writeNotebookCryptBackup fails after the notebook's conf.json was already updated to the new key material. The per-notebook backup is the redundancy that lets decryptBoxCrypt fall back and repair conf, so failing to refresh it aborts with errMasterPasswordMigrationPending (localized 320); the manifest survives for restart recovery.","triggerScenarios":"The backup file under the notebook crypto backup path cannot be written: disk full, permission denied, or the backup file locked by another process during the change loop.","commonSituations":"Backup directory made read-only or excluded incorrectly; disk exhaustion partway through the per-notebook backup writes; file-level locks from backup software.","solutions":["Restore writability of the notebook crypt backup location named in the logs","Restart SiYuan - recovery re-runs the manifest and rewrites both conf and backups; verify with the new password afterwards","Keep enough free space and pause third-party file locks before rotating the master password"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isMigrationPendingErr(err error) bool {\n    return errors.Is(err, errMasterPasswordMigrationPending) // in-package; outside use string prefix check\n}","tryCatchPattern":"if err := model.ChangeMasterPassword(oldPw, newPw); isMigrationPendingErr(err) {\n    instructUserRestart() // backup refresh failed; manifest recovery rewrites conf+backup pairs\n    return\n}","preventionTips":["Verify the notebook crypt backup directory is writable before starting the change","Do not mark backup files read-only with external backup tools while SiYuan runs","Keep free disk headroom for every per-notebook backup rewrite"],"tags":["encryption","master-password","migration","io","backup"],"backgroundTag":"master-password-migration-pending","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}