{"record":{"id":"2e5b8aeca1dfab71","repo":"tailscale/tailscale","slug":"empty-user-uid-in-connection-identity","errorCode":null,"errorMessage":"empty user uid in connection identity","messagePattern":"empty user uid in connection identity","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ipn/ipnlocal/local.go","lineNumber":4602,"sourceCode":"// Currently (as of 2024-08-26), this is only used on Windows.\n// We plan to remove it as part of the multi-user and unattended mode improvements\n// as we progress on tailscale/corp#18342.\nfunc (b *LocalBackend) CheckIPNConnectionAllowed(actor ipnauth.Actor) error {\n\tb.mu.Lock()\n\tdefer b.mu.Unlock()\n\tif b.pm.CurrentUserID() == \"\" {\n\t\t// There's no \"current user\" yet; allow the connection.\n\t\treturn nil\n\t}\n\t// Always allow Windows SYSTEM user to connect,\n\t// even if Tailscale is currently being used by another user.\n\tif actor.IsLocalSystem() {\n\t\treturn nil\n\t}\n\n\tuid := actor.UserID()\n\tif uid == \"\" {\n\t\treturn errors.New(\"empty user uid in connection identity\")\n\t}\n\tif uid == b.pm.CurrentUserID() {\n\t\t// The connection is from the current user; allow it.\n\t\treturn nil\n\t}\n\n\t// The connection is from a different user; block it.\n\tvar reason string\n\tif b.pm.CurrentPrefs().ForceDaemon() {\n\t\treason = \"running in server mode\"\n\t} else {\n\t\treason = \"already in use\"\n\t}\n\treturn fmt.Errorf(\"Tailscale %s (%q); connection from %q not allowed\",\n\t\treason, b.tryLookupUserName(string(b.pm.CurrentUserID())),\n\t\tb.tryLookupUserName(string(uid)))\n}\n","sourceCodeStart":4584,"sourceCodeEnd":4620,"githubUrl":"https://github.com/tailscale/tailscale/blob/cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042/ipn/ipnlocal/local.go#L4584-L4620","documentation":"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.","triggerScenarios":"Connecting an actor with actor.UserID() == \"\" while b.pm.CurrentUserID() != \"\" and !actor.IsLocalSystem().","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Go (ipnserver authors): reject unusable identities before acceptance\nif uid := actor.UserID(); uid == \"\" && !actor.IsLocalSystem() && b.pm.CurrentUserID() != \"\" {\n\t// block the connection up front with a clear message\n}","typeGuard":"func isEmptyConnIdentity(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"empty user uid in connection identity\")\n}","tryCatchPattern":"if err := b.checkConnectionIdentity(actor); err != nil {\n\tif isEmptyConnIdentity(err) { // ask the client to reconnect with full identity\n\t\treturn err }\n\treturn err\n}","preventionTips":["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"],"tags":["windows","authn","localapi","identity"],"backgroundTag":null,"analyzedSha":"cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042","analyzedAt":"2026-08-15T19:58:31.583Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}