siyuan-note/siyuan · error

new password must not be empty

Error message

new password must not be empty

What it means

ChangeMasterPassword rejects an empty new password. A master password is the root of the KEK derivation for encrypted notebooks, so a zero-length value would produce an unusable/weakened key hierarchy and is refused before any re-wrap work begins.

Solutions

  1. Validate the new password is non-empty (and meets strength requirements) in the caller before invoking ChangeMasterPassword
  2. Return a user-facing message prompting entry of a new password
  3. Check for whitespace-only inputs too, since the kernel only rejects zero length

Example fix

// before
await changeMasterPassword(oldPw, newPwInput.value)
// after
if (!newPwInput.value.trim()) throw new Error(window.siyuan.languages.passwordRequired)
await changeMasterPassword(oldPw, newPwInput.value)
Defensive patterns

Strategy: validation

Validate before calling

if len(newPassword) === 0 { throw new Error("new password is required") }
await changeMasterPassword(oldPassword, newPassword)

Try / catch

try { await changeMasterPassword(oldPw, newPw) } catch (e) { if (e.message.includes("new password must not be empty")) { showError("请输入新密码") } }

Prevention

When it happens

Trigger: Calling model.ChangeMasterPassword(oldPassword, "") from a UI/API path that did not validate the new password field, e.g. user submitted a blank form or a script passed an empty string.

Common situations: Frontend form submitted without client-side validation; automation scripts setting a password variable that is empty; localization/UI bugs clearing the field.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/29d27bf6a2027573. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/crypto.go:1710

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 9f775e8a12)