siyuan-note/siyuan · error

new password must not be empty

Error message

new password must not be empty

What it means

Thrown by ChangeMasterPassword when newPassword is empty. This is the first validation before any crypto work begins. An empty master password would produce a deterministic KEK and is explicitly rejected as a security invariant.

Source

Thrown at kernel/model/crypto.go:1685

func ClearDEK(boxID string) {
	LockBox(boxID)
}

// ChangeMasterPassword 改主密码:用旧密码校验后,用新密码派生新 KEK,
// 重新加密 verifier,并把所有加密笔记本的 WrappedDEK 用新 KEK 重新包络后写回各自的 BoxConf。
//
// 使用两阶段提交确保崩溃后可恢复:
//
//	Phase 0: 预计算所有新 WrappedDEK(内存)
//	Phase 1: 写入 migration manifest
//	Phase 2: 切换全局 verifier
//	Phase 3: 写入各 box conf + backup
//	Phase 4: 清除 manifest
//
// 注意:必须在所有加密笔记本都已 Unmount 的状态下调用(DEK 不在内存),否则新旧 KEK 切换会让缓存与磁盘不一致。
func ChangeMasterPassword(oldPassword, newPassword string) error {
	if len(newPassword) == 0 {
		return errors.New("new password must not be empty")
	}

	notebookCryptoMu.Lock()
	defer notebookCryptoMu.Unlock()

	// 改密期间不能有已 Mount 的加密笔记本(DEK 在内存),否则新旧 KEK 切换会让缓存与磁盘不一致
	cachedDEKsLock.RLock()
	dekCount := len(cachedDEKs)
	cachedDEKsLock.RUnlock()
	if dekCount > 0 {
		return errors.New("cannot change master password while encrypted notebooks are unlocked (DEKs in memory), lock them first")
	}

	oldKEK, err := deriveKEK(oldPassword)
	if err != nil {
		return err
	}
	defer zeroAndClear(oldKEK)

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Provide a non-empty newPassword in the API request body.
  2. Add frontend validation to reject empty new-password before submitting the API call.
  3. If calling programmatically, validate the password is non-empty before invoking ChangeMasterPassword.

Example fix

// before
model.ChangeMasterPassword(oldPassword, "")
// after
if newPassword == "" {
    return errors.New("new password must not be empty")
}
model.ChangeMasterPassword(oldPassword, newPassword)
Defensive patterns

Strategy: validation

Validate before calling

// Validate before calling ChangeMasterPassword:
if newPassword == "" {
    return errors.New("new password must not be empty")
}
model.ChangeMasterPassword(oldPassword, newPassword)

Prevention

When it happens

Trigger: Called via the HTTP API changeMasterPassword (POST /api/notebook/changeMasterPassword) with an empty newPassword field in the JSON body. Also reachable from mobile/harmony bindings that call ChangeMasterPassword directly.

Common situations: Frontend form validation bug that submits an empty new-password field. API consumer sends {"oldPassword":"...","newPassword":""} due to a serialization error. A test harness or script calls ChangeMasterPassword with an empty string.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/29d27bf6a2027573. Report an issue: GitHub.