juanfont/headscale · warning · util.ErrUsernameTooShort

username must be at least 2 characters long

Error message

username must be at least 2 characters long

What it means

ErrUsernameTooShort (hscontrol/util/dns.go:30) is returned by ValidateUsername when the username is shorter than 2 characters. Usernames become MagicDNS labels / identity names, and single- or zero-character names are rejected because they cannot form a valid identity label. It is the first check in ValidateUsername (length, then first-letter, then '@' count, then charset).

Source

Thrown at hscontrol/util/dns.go:30

	"go4.org/netipx"
	"tailscale.com/util/dnsname"
)

const (
	ByteSize          = 8
	ipv4AddressLength = 32
	ipv6AddressLength = 128

	// LabelHostnameLength is the maximum length for a DNS label,
	// value related to RFC 1123 and 952.
	LabelHostnameLength = 63
)

// DNS validation errors. Hostname-side validation lives on
// `tailscale.com/util/dnsname` and [state.NodeStore] collision handling; only
// the username-side errors stay in this package.
var (
	ErrUsernameTooShort        = errors.New("username must be at least 2 characters long")
	ErrUsernameMustStartLetter = errors.New("username must start with a letter")
	ErrUsernameTooManyAt       = errors.New("username cannot contain more than one '@'")
	ErrUsernameInvalidChar     = errors.New("username contains invalid character")
)

// ValidateUsername checks if a username is valid.
// It must be at least 2 characters long, start with a letter, and contain
// only letters, numbers, hyphens, dots, and underscores.
// It cannot contain more than one '@'.
// It cannot contain invalid characters.
func ValidateUsername(username string) error {
	// Ensure the username meets the minimum length requirement
	if len(username) < 2 {
		return ErrUsernameTooShort
	}

	// Ensure the username starts with a letter
	if !unicode.IsLetter(rune(username[0])) {

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Use a username of at least 2 characters
  2. If the name comes from OIDC, map a different claim or normalize it before it reaches user creation
  3. Pre-check with util.ValidateUsername in your own tooling before calling the API

Example fix

# before
headscale users create a

# after
headscale users create alice
Defensive patterns

Strategy: validation

Validate before calling

if len(username) < 2 {
	return fmt.Errorf("username %q too short: %w", username, util.ErrUsernameTooShort)
}
if err := util.ValidateUsername(username); err != nil { // full check
	return err
}

Try / catch

if err := util.ValidateUsername(name); err != nil {
	if errors.Is(err, util.ErrUsernameTooShort) {
		name = defaultPrefix + name // pad to >= 2 chars per your convention
	} else {
		return err
	}
}

Prevention

When it happens

Trigger: Calling util.ValidateUsername with a 0- or 1-character string; reached from user-creation paths (CLI `headscale users create x`, OIDC login mapping a provider sub/email to a name, API user creation).

Common situations: Creating a test user with a one-letter name; an OIDC provider returning an unusual claim (e.g. single-char preferred_username); scripted provisioning that derived an empty username from an email local-part.

Related errors


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/47456c1887c0aa80. Report an issue: GitHub.