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
- Ensure the connecting client resolves a real user ID (valid Windows SID) before connecting
- Connect from the SYSTEM/service context, which is always allowed
- 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
- Verify the connection identity resolves a SID before accepting the actor
- Test multi-user Windows flows with fully initialized actors
- Allow SYSTEM connections as the supported administrative path
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
- the target profile does not belong to the user
- must be a Windows local admin to serve a path or Unix socket
- update must be run as Administrator you can run the command
- expected at least one argument
- expected at least one argument after method
AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15).
Data as JSON: /api/errors/2e5b8aeca1dfab71.
Report an issue: GitHub.