juanfont/headscale · error · ErrInvalidAuthIDLength
auth ID has invalid length
Error message
auth ID has invalid length
What it means
ErrInvalidAuthIDLength is a sentinel error in hscontrol/types/common.go:26 returned by AuthID.Validate() (common.go:75-79) when an AuthID string's total length is not exactly AuthIDLength (38 = 14-char prefix 'hskey-authreq-' + 24 random chars). AuthIDFromString routes through Validate, so parsing any malformed-length ID fails with this error, wrapped with expected vs actual length.
Source
Thrown at hscontrol/types/common.go:26
"fmt"
"runtime"
"strings"
"sync/atomic"
"time"
"tailscale.com/util/rands"
)
const (
SelfUpdateIdentifier = "self-update"
DatabasePostgres = "postgres"
DatabaseSqlite = "sqlite3"
)
// Common errors.
var (
ErrCannotParsePrefix = errors.New("cannot parse prefix")
ErrInvalidAuthIDLength = errors.New("auth ID has invalid length")
ErrInvalidAuthIDPrefix = errors.New("auth ID has invalid prefix")
)
const (
authIDPrefix = "hskey-authreq-"
authIDRandomLength = 24
// AuthIDLength is the total length of an AuthID: 14 (prefix) + 24 (random).
AuthIDLength = 38
)
type AuthID string
func NewAuthID() (AuthID, error) {
return AuthID(authIDPrefix + rands.HexString(authIDRandomLength)), nil
}
func MustAuthID() AuthID {
rid, err := NewAuthID()View on GitHub (pinned to 565fd254d0)
Solutions
- Pass the auth ID through unmodified from registration URL to AuthIDFromString
- Always generate IDs with types.NewAuthID() instead of constructing strings manually
- Strip whitespace/newlines before parsing if IDs transit logs or terminals
- Check for proxy/header truncation if IDs arrive consistently shortened
Example fix
// before
id, err := types.AuthIDFromString("hskey-authreq-short") // wrong length
// after
id, err := types.AuthIDFromString(rawURLParam) // pass the exact generated value Defensive patterns
Strategy: validation
Validate before calling
const authIDLen = 38
if len(s) != authIDLen {
return errors.New("auth ID length invalid")
} Type guard
func isValidAuthID(s string) bool {
return strings.HasPrefix(s, "hskey-authreq-") && len(s) == types.AuthIDLength
} Try / catch
if _, err := types.AuthIDFromString(s); err != nil {
if errors.Is(err, types.ErrInvalidAuthIDLength) { return 400 }
} Prevention
- Pass auth IDs end-to-end without manual edits
- Generate IDs only via types.NewAuthID()
When it happens
Trigger: Calling types.AuthIDFromString on a truncated or padded auth request ID (e.g. 37 or 39 chars); hand-building an auth ID instead of using NewAuthID; IDs mangled by URL encoding/whitespace before parsing.
Common situations: Truncation of the registration URL parameter by proxies or clients; copy-paste of auth URLs losing characters; tests constructing IDs via string concatenation with wrong random-part length.
Related errors
- auth ID has invalid prefix
- failed to parse auth-key
- registration expired
- failed to parse ApiKey
- failed to parse oauth client secret
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/3f7152b66733ef58.
Report an issue: GitHub.