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

  1. Pass the auth ID through unmodified from registration URL to AuthIDFromString
  2. Always generate IDs with types.NewAuthID() instead of constructing strings manually
  3. Strip whitespace/newlines before parsing if IDs transit logs or terminals
  4. 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

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


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