{"record":{"id":"a75cd92f44c8bb5b","repo":"siyuan-note/siyuan","slug":"master-password-migration-is-pending-master-passw-a75cd9","errorCode":null,"errorMessage":"master password migration is pending: Master password change partially failed. Please restart SiYuan to complete recovery. Detail: %s: save conf failed: %s","messagePattern":"master password migration is pending: Master password change partially failed\\. Please restart SiYuan to complete recovery\\. Detail: (.+?): save conf failed: (.+?)","errorType":"exception","errorClass":"errMasterPasswordMigrationPending","httpStatus":null,"severity":"critical","filePath":"kernel/model/crypto.go","lineNumber":1810,"sourceCode":"\t\t\t\tboxConf.BoxCrypt = &conf.BoxEncryption{\n\t\t\t\t\tWrappedDEK: entry.NewWrappedDEK,\n\t\t\t\t\tWrapNonce:  entry.NewWrapNonce,\n\t\t\t\t\tSpec:       entry.NewSpec,\n\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","sourceCodeStart":1792,"sourceCodeEnd":1828,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/model/crypto.go#L1792-L1828","documentation":"Returned by ChangeMasterPassword Phase 3 (crypto.go:1805-1812) when the main conf.json write for a notebook fails after its BoxCrypt fields were updated in memory to the new KEK's WrappedDEK/Spec/WrapNonce/Metadata. It wraps errMasterPasswordMigrationPending (localized 320) with the box ID and the save error; the migration manifest ensures a restart can finish the job.","triggerScenarios":"box.SaveConf errors while persisting the re-wrapped key material: disk full, read-only file, permission denied, or an external process holding conf.json during the rewrite loop.","commonSituations":"Password change over many notebooks running out of space midway; AV/sync locking conf.json files one by one; workspace on flaky storage.","solutions":["Resolve the disk/permission/lock condition reported in the detail string","Restart SiYuan to let migration recovery complete, then verify with the new master password","Retry the password change only after recovery reports clean; ensure ample free space and paused sync/AV during the operation"],"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    // conf save failed mid-loop: do not retry the change in-session; restart and verify\n    instructUserRestart()\n    return\n}","preventionTips":["Free disk space exceeding the total size of all notebook conf files before the change","Pause sync/AV file locks on the workspace during password rotation","Treat any single SaveConf failure as 'restart and recover', never as 'retry immediately'"],"tags":["encryption","master-password","migration","io","conf"],"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"}