siyuan-note/siyuan · error · errMasterPasswordMigrationPending

%w: %v (errMasterPasswordMigrationPending)

Error message

%w: %v (errMasterPasswordMigrationPending)

What it means

During a pending master-password migration, deriveKEK wraps errMasterPasswordMigrationPending with the underlying failure: after the new password verified, decrypting history KEKs, verifying boxes/history, or saveNotebookCryptoBackup failed — here specifically the final authenticated global backup could not be written. The migration stays pending and the caller is told recovery must finish before the change is complete.

Source

Thrown at kernel/model/crypto.go:1310

			logging.LogInfof("repaired notebook crypto configuration from authenticated backup")
		} else if !backupAuthenticated {
			// 同步备份可能属于另一轮完整改密;只要本地配置仍与全部笔记本一致,就继续使用本地配置,
			// 不覆盖候选备份,等待其余 WrappedDEK 同步完成后由新密码采用。
			logging.LogWarnf("notebook crypto backup differs from usable local configuration; keeping both candidates")
		}
	}

	if migrationPending {
		// 崩溃恢复后的首次新密码验证:确认所有笔记本都已切换到新 KEK,再生成带认证的全局备份并结束迁移。
		keys, keyErr := decryptHistoryKEKs(kek, nc.HistoryKEKs)
		clearHistoryKEKs(keys)
		if keyErr != nil || !verifyKEKAgainstExistingBoxes(kek, nil) || !verifyKEKAgainstEncryptedHistory(kek, &nc) {
			zeroAndClear(kek)
			return nil, errMasterPasswordMigrationPending
		}
		if err = saveNotebookCryptoBackup(kek); err != nil {
			zeroAndClear(kek)
			return nil, fmt.Errorf("%w: %v", errMasterPasswordMigrationPending, err)
		}
		removeMasterPasswordMigration()
	}
	return kek, nil
}

// decryptBoxCrypt 用 KEK 解密 box 的 WrappedDEK。优先使用 GetBoxEncryption 的结果(conf → backup fallback),
// 若解密失败则尝试 backup 中不同的 WrappedDEK。
// 返回解密后的 DEK 和实际使用的 BoxCrypt(可能来自 backup)。
// 若 backup 被使用会自动修复 conf.json 和刷新 backup。
func decryptBoxCrypt(boxID string, kek []byte) (dek []byte, boxCrypt *conf.BoxEncryption, err error) {
	boxCrypt, err = GetBoxEncryption(boxID)
	if err != nil || boxCrypt == nil || len(boxCrypt.WrappedDEK) == 0 {
		return nil, nil, fmt.Errorf("no encrypted key material for box [%s]", boxID)
	}

	nc := currentNotebookCrypto()
	dek, err = decryptWrappedDEKWithHistory(boxID, boxCrypt, kek, nc)

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Fix the underlying write problem (free disk space, check file/dir permissions, close locking processes) and unlock again with the new password so migration completes
  2. Ensure the workspace Data directory is writable by the SiYuan process, then retry
  3. If migration cannot complete, restore the workspace from a pre-migration backup; note the wrapped error message reports the exact underlying cause

Example fix

// before (retrying blindly while Data dir is read-only)
POST /api/notebook/unlockEncryptedBox {password: newPassword}
// after
chmod u+w <workspace>/Data; df -h <workspace>  # then retry the same unlock with the new password
Defensive patterns

Strategy: try-catch

Validate before calling

// Before resuming a pending migration, verify the workspace can write the backup file
if err := checkWorkspaceWritable(util.DataDir); err != nil {
    return fmt.Errorf("cannot complete master-password migration: %w", err)
}

Try / catch

kek, err := deriveKEK(newPassword)
if errors.Is(err, errMasterPasswordMigrationPending) {
    log.Printf("migration still pending: %v — fix the wrapped cause (disk/permissions) and unlock again", err)
    return
}

Prevention

When it happens

Trigger: First unlock with the new password after a crash/interruption during ChangeMasterPassword (migrationPending true), when saveNotebookCryptoBackup(kek) returns an error — typically a file-write failure in the Data directory (disk full, permissions, read-only volume).

Common situations: Disk full or read-only workspace volume; antivirus/backup software locking the backup file; permission changes on the Data directory after migration started.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/af89f1c2b601a209. Report an issue: GitHub.