MHSanaei/3x-ui · warning

password can not be empty

Error message

password can not be empty

What it means

The sibling guard in UpdateFirstUser: the password argument is empty, so the function refuses before hashing. Because UpdateFirstUser always writes BOTH username and password in one Updates() call, an empty password would not be skipped — it would overwrite the admin's password hash with the bcrypt of "", effectively breaking admin auth.

Source

Thrown at internal/web/service/panel/user.go:147

		_ = s.settingService.SetTwoFactorEnable(false)
		_ = s.settingService.SetTwoFactorToken("")
	}

	return db.Model(model.User{}).
		Where("id = ?", id).
		Updates(map[string]any{
			"username":    username,
			"password":    hashedPassword,
			"login_epoch": gorm.Expr("login_epoch + 1"),
		}).
		Error
}

func (s *UserService) UpdateFirstUser(username string, password string) error {
	if username == "" {
		return errors.New("username can not be empty")
	} else if password == "" {
		return errors.New("password can not be empty")
	}
	hashedPassword, er := crypto.HashPasswordAsBcrypt(password)

	if er != nil {
		return er
	}

	db := database.GetDB()
	user := &model.User{}
	err := db.Model(model.User{}).First(user).Error
	if database.IsNotFound(err) {
		user.Username = username
		user.Password = hashedPassword
		return db.Model(model.User{}).Create(user).Error
	} else if err != nil {
		return err
	}
	user.Username = username

View on GitHub (pinned to ad32144c42)

Solutions

  1. Always pass the intended password (current or new) whenever this endpoint is used — it updates both fields atomically
  2. If only the username should change, use the endpoint/flow that updates credentials separately rather than emptying the password
  3. Validate non-empty password at the form/API layer before the call

Example fix

// before
err := userService.UpdateFirstUser("admin", "")

// after
err := userService.UpdateFirstUser("admin", req.Password)
// with earlier validation: if req.Password == "" { return 400 }
Defensive patterns

Strategy: validation

Validate before calling

if password == "" {
    return errors.New("password required")
}
err := userService.UpdateFirstUser(username, password)

Prevention

When it happens

Trigger: Calling UpdateFirstUser(username, "") — a settings form where the password input was left blank, or an API client that only intended to rename the user and passed no password.

Common situations: 'Change username only' flows that reuse the update endpoint without re-sending the current password; frontend password field cleared before submit; migration scripts that copy a user with no password set.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/560e481e60a53e29. Report an issue: GitHub.