gotify/server · error

password must not be empty

Error message

password must not be empty

What it means

Validation error from password.ValidateNewPassword in auth/password/password.go: an empty password string was supplied where a new password is required. The function is called by CreateUser, ChangePassword, and the user-update handler before hashing, so user creation or password change is rejected with HTTP 400.

Source

Thrown at auth/password/password.go:11

package password

import (
	"errors"

	"golang.org/x/crypto/bcrypt"
)

func ValidateNewPassword(pw string) error {
	if pw == "" {
		return errors.New("password must not be empty")
	}
	if len([]byte(pw)) > 72 {
		return bcrypt.ErrPasswordTooLong
	}
	return nil
}

// CreatePassword returns a hashed version of the given password.
func CreatePassword(pw string, strength int) ([]byte, error) {
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(pw), strength)
	return hashedPassword, err
}

// ComparePassword compares a hashed password with its possible plaintext equivalent.
func ComparePassword(hashedPassword, password []byte) bool {
	return bcrypt.CompareHashAndPassword(hashedPassword, password) == nil
}

View on GitHub (pinned to 14bfc25627)

Solutions

  1. Omit the pass/pass field entirely when you don't want to change the password (empty string in update means 'no change' only if the handler checks; for create a real password is required)
  2. Send a non-empty password when creating a user or changing a password
  3. Also keep the password <= 72 bytes since the same validator enforces bcrypt's length limit

Example fix

// before
await api.updateUser(id, { name: 'bob', pass: '' });
// after: only send pass when actually changing it
const payload = { name: 'bob' };
if (newPassword) payload.pass = newPassword;
await api.updateUser(id, payload);
Defensive patterns

Strategy: validation

Validate before calling

function validateNewPassword(pw) {
  if (typeof pw !== 'string' || pw.length === 0) throw new Error('password must not be empty');
  if (Buffer.byteLength(pw, 'utf8') > 72) throw new Error('password longer than 72 bytes');
  return pw;
}
validateNewPassword(newPassword);

Type guard

function isValidPassword(pw) {
  return typeof pw === 'string' && pw.length > 0 && Buffer.byteLength(pw, 'utf8') <= 72;
}

Try / catch

try {
  await api.createUser({ name, pass: pw });
} catch (e) {
  if (e.status === 400 && /password/.test(e.message)) {
    throw new ValidationError('password rejected by server: ' + e.message);
  }
  throw e;
}

Prevention

When it happens

Trigger: POST /users (admin create user) or password-change endpoint with pass == "" or the pass field omitted; user-update (PUT) setting a password to an empty string instead of leaving it out.

Common situations: Client sends JSON without the pass field and the server treats empty string as 'set password'; forms with an optional password field submit empty values; API clients defaulting missing fields to empty strings in serialization.

Related errors


AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05). Data as JSON: /api/errors/574e972ad3a694a6. Report an issue: GitHub.