juanfont/headscale · warning · util.ErrUsernameTooManyAt
username cannot contain more than one '@'
Error message
username cannot contain more than one '@'
What it means
ErrUsernameTooManyAt (hscontrol/util/dns.go:32) is returned by ValidateUsername when the username contains more than one '@' character. Exactly one '@' is tolerated so that email-style names (user@domain) can be used, but a second '@' would break label derivation for MagicDNS and cannot be represented as a valid identity name.
Source
Thrown at hscontrol/util/dns.go:32
)
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 ErrUsernameMustStartLetter
}View on GitHub (pinned to 565fd254d0)
Solutions
- Use at most one '@' — strip the duplicated domain part before creating the user
- For OIDC, pick a claim that is a bare username, or normalize the claim value in your IdP
- Pre-validate with util.ValidateUsername in automation
Example fix
// before username := email + "@example.com" // user@example.com@example.com // after username := localPart(email) // user
Defensive patterns
Strategy: validation
Validate before calling
if strings.Count(username, "@") > 1 {
return fmt.Errorf("username %q has multiple '@': %w", username, util.ErrUsernameTooManyAt)
} Prevention
- Never append '@domain' to a value that may already contain '@'
- Normalize OIDC claims (strip domain) before user creation
When it happens
Trigger: Calling util.ValidateUsername with strings like "a@b@c" or "user@@example.com"; typically reached via user creation (CLI/API) or OIDC claim mapping that concatenates a domain onto an already-qualified name.
Common situations: OIDC providers returning 'name@tenant@domain' style claims; provisioning scripts appending '@company.com' to a username that already includes '@company.com'; copy/paste artifacts adding a stray '@'.
Related errors
- username must be at least 2 characters long
- username must start with a letter
- 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/19ab9925a3915f31.
Report an issue: GitHub.