tailscale/tailscale · error · ErrBadSrcName

%w, actual length is %d

Error message

%w, actual length is %d

What it means

logonAs rejects a token source name whose length is 0 or greater than _TOKEN_SOURCE_LENGTH (8), the fixed size of TOKEN_SOURCE.SourceName. The error wraps the ErrBadSrcName sentinel and reports the actual length, so errors.Is(err, ErrBadSrcName) detects it.

Source

Thrown at util/winutil/s4u/lsa_windows.go:260

	if err != nil {
		return username, false, err
	}

	if strings.EqualFold(before, comp) {
		return after, false, nil
	}
	return username, true, nil
}

// logonAs performs a S4U logon for u on behalf of srcName, and returns an
// access token for the user if successful. srcName must be non-empty, ASCII,
// and no more than 8 characters long. If srcName does not meet this criteria,
// LogonAs will return ErrBadSrcName wrapped with additional information; use
// errors.Is to check for it. When capLevel == CapCreateProcess, the logon
// enforces the user's logon hours policy (when present).
func (ls *lsaSession) logonAs(srcName string, u *user.User, capLevel CapabilityLevel) (token windows.Token, err error) {
	if ln := len(srcName); ln == 0 || ln > _TOKEN_SOURCE_LENGTH {
		return 0, fmt.Errorf("%w, actual length is %d", ErrBadSrcName, ln)
	}
	if err := checkASCII(srcName); err != nil {
		return 0, fmt.Errorf("%w: %v", ErrBadSrcName, err)
	}

	sanitizedUserName, isDomainUser, err := checkDomainAccount(u.Username)
	if err != nil {
		return 0, err
	}
	if isDomainUser && !winenv.IsDomainJoined() {
		return 0, fmt.Errorf("%w: cannot logon as domain user without being joined to a domain", os.ErrInvalid)
	}

	var pkgID uint32
	var authInfo unsafe.Pointer
	var authInfoLen uint32
	enforceLogonHours := capLevel == CapCreateProcess
	if isDomainUser {

View on GitHub (pinned to 6e0912f979)

Solutions

  1. Use a constant source name that is 1-8 ASCII characters (e.g. "tssvc")
  2. Validate length at config load time so the failure surfaces before any LSA work
  3. Handle ErrBadSrcName with errors.Is to give a precise error message

Example fix

// before
srcName := "my-long-service-name" // 20 chars

// after
const srcName = "tssvc" // <= 8 chars, ASCII
// or: if len(srcName) == 0 || len(srcName) > 8 { return cfgError }
Defensive patterns

Strategy: validation

Validate before calling

const maxSrcName = 8 // _TOKEN_SOURCE_LENGTH
if len(srcName) == 0 || len(srcName) > maxSrcName {
    return fmt.Errorf("srcName must be 1-%d ASCII characters", maxSrcName)
}

Try / catch

sess, err := s4u.Login(logf, srcName, u, capLevel)
if err != nil {
    if errors.Is(err, s4u.ErrBadSrcName) {
        return fmt.Errorf("bad srcName (len=%d); use 1-8 ASCII chars", len(srcName))
    }
    return err
}

Prevention

When it happens

Trigger: Calling s4u.Login / ListGroupIDsForSSHPreAuthOnly with an empty srcName, or with a long human-readable service name (9+ characters) instead of a short source tag.

Common situations: Passing service display names ("My Company Agent") where an 8-char tag is required; defaulting the argument to the empty string when config is missing.

Related errors


AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18). Data as JSON: /api/errors/220f552c52281b8f. Report an issue: GitHub.