juanfont/headscale · warning · util.ErrUsernameMustStartLetter
username must start with a letter
Error message
username must start with a letter
What it means
ErrUsernameMustStartLetter (hscontrol/util/dns.go:31) is returned by ValidateUsername when the first character of the username is not an ASCII letter. This mirrors DNS-label and classic username rules (RFC 1123/952 heritage referenced by the constants in dns.go): names must start with a letter, then may contain letters, digits, hyphens, dots, underscores, and one '@'.
Source
Thrown at hscontrol/util/dns.go:31
"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])) {
return ErrUsernameMustStartLetterView on GitHub (pinned to 565fd254d0)
Solutions
- Prefix or rename so the name starts with a letter (e.g. u123456 instead of 123456)
- For OIDC, transform the incoming claim (prefix with a letter) before user creation
- Run util.ValidateUsername in provisioning scripts to fail before the API call
Example fix
# before headscale users create 1alice # after headscale users create alice1
Defensive patterns
Strategy: validation
Validate before calling
func startsWithLetter(s string) bool {
return len(s) > 0 && ((s[0] >= 'a' && s[0] <= 'z') || (s[0] >= 'A' && s[0] <= 'Z'))
}
if !startsWithLetter(username) {
return fmt.Errorf("username %q must start with a letter", username)
} Prevention
- Prefix digit-leading generated names with a letter (u123456)
- Validate via util.ValidateUsername before calling user-creation APIs
When it happens
Trigger: Calling util.ValidateUsername with names like "1alice", "_bob", "-carol", or ".dave" — any leading non-letter. Reached from CLI user creation, API user creation, and OIDC-derived usernames.
Common situations: Provisioning machine-generated usernames that begin with a digit (e.g. student ID "123456"); email local-parts starting with a dot or digit; import scripts from systems with laxer naming rules.
Related errors
- username must be at least 2 characters long
- username cannot contain more than one '@'
- username contains invalid character: '%c'
- is not valid
- username must contain @
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/4f36a29f2fb28338.
Report an issue: GitHub.