tailscale/tailscale · error

empty user uid in connection identity

Error message

empty user uid in connection identity

What it means

checkConnectionIdentity returns this when a LocalAPI client connects while another user is 'current', the actor is not local SYSTEM, and the actor reports an empty UserID — the identity is unusable, so the connection is blocked to protect the current user's session.

Source

Thrown at ipn/ipnlocal/local.go:4602

// Currently (as of 2024-08-26), this is only used on Windows.
// We plan to remove it as part of the multi-user and unattended mode improvements
// as we progress on tailscale/corp#18342.
func (b *LocalBackend) CheckIPNConnectionAllowed(actor ipnauth.Actor) error {
	b.mu.Lock()
	defer b.mu.Unlock()
	if b.pm.CurrentUserID() == "" {
		// There's no "current user" yet; allow the connection.
		return nil
	}
	// Always allow Windows SYSTEM user to connect,
	// even if Tailscale is currently being used by another user.
	if actor.IsLocalSystem() {
		return nil
	}

	uid := actor.UserID()
	if uid == "" {
		return errors.New("empty user uid in connection identity")
	}
	if uid == b.pm.CurrentUserID() {
		// The connection is from the current user; allow it.
		return nil
	}

	// The connection is from a different user; block it.
	var reason string
	if b.pm.CurrentPrefs().ForceDaemon() {
		reason = "running in server mode"
	} else {
		reason = "already in use"
	}
	return fmt.Errorf("Tailscale %s (%q); connection from %q not allowed",
		reason, b.tryLookupUserName(string(b.pm.CurrentUserID())),
		b.tryLookupUserName(string(uid)))
}

View on GitHub (pinned to cfe32b8be6)

Solutions

  1. Ensure the connecting client resolves a real user ID (valid Windows SID) before connecting
  2. Connect from the SYSTEM/service context, which is always allowed
  3. Disconnect or switch the current user session first so the no-current-user fast path applies
Defensive patterns

Strategy: validation

Validate before calling

// Go (ipnserver authors): reject unusable identities before acceptance
if uid := actor.UserID(); uid == "" && !actor.IsLocalSystem() && b.pm.CurrentUserID() != "" {
	// block the connection up front with a clear message
}

Type guard

func isEmptyConnIdentity(err error) bool {
	return err != nil && strings.Contains(err.Error(), "empty user uid in connection identity")
}

Try / catch

if err := b.checkConnectionIdentity(actor); err != nil {
	if isEmptyConnIdentity(err) { // ask the client to reconnect with full identity
		return err }
	return err
}

Prevention

When it happens

Trigger: Connecting an actor with actor.UserID() == "" while b.pm.CurrentUserID() != "" and !actor.IsLocalSystem().

Common situations: Windows connection-identity lookups that fail to resolve a SID (unusual session tokens, broken LSA lookup) while a user profile is active; tests with uninitialized actors connecting after a user logged in.

Related errors


AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15). Data as JSON: /api/errors/2e5b8aeca1dfab71. Report an issue: GitHub.