{"record":{"id":"44cea1eddb13ab46","repo":"tailscale/tailscale","slug":"errtaggedremotesource","errorCode":"errTaggedRemoteSource","errorMessage":"tagged-remote-source","messagePattern":"tagged-remote-source","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/web/auth.go","lineNumber":78,"sourceCode":"\t}\n\treturn true\n}\n\n// isExpired reports true if s is expired.\n// 2023-10-05: Sessions expire by default 30 days after creation.\nfunc (s *browserSession) isExpired(now time.Time) bool {\n\treturn !s.Created.IsZero() && now.After(s.expires())\n}\n\n// expires reports when the given session expires.\nfunc (s *browserSession) expires() time.Time {\n\treturn s.Created.Add(sessionCookieExpiry)\n}\n\nvar (\n\terrNoSession          = errors.New(\"no-browser-session\")\n\terrNotUsingTailscale  = errors.New(\"not-using-tailscale\")\n\terrTaggedRemoteSource = errors.New(\"tagged-remote-source\")\n\terrTaggedLocalSource  = errors.New(\"tagged-local-source\")\n\terrNotOwner           = errors.New(\"not-owner\")\n)\n\n// getSession retrieves the browser session associated with the request,\n// if one exists.\n//\n// An error is returned in any of the following cases:\n//\n//   - (errNotUsingTailscale) The request was not made over tailscale.\n//\n//   - (errNoSession) The request does not have a session.\n//\n//   - (errTaggedRemoteSource) The source is remote (another node) and tagged.\n//     Users must use their own user-owned devices to manage other nodes'\n//     web clients.\n//\n//   - (errTaggedLocalSource) The source is local (the same node) and tagged.","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/tailscale/tailscale/blob/6e0912f97994f927632b34ae9e63b53d6516a6ac/client/web/auth.go#L60-L96","documentation":"errTaggedRemoteSource is returned when WhoIs identifies the requesting node as tagged and it is not the node running the web client. Tagged nodes have machine identity without an owning user, so they cannot hold or create a user browser session. The web client therefore refuses them outright.","triggerScenarios":"A device registered with --advertise-tags (e.g. tag:server) connects to the web client port of another node; an ACL rule grants a tagged device access to the web client's port; automation running on a tagged node points a browser or HTTP client at the web UI.","commonSituations":"Servers tagged for service ACLs that can also reach the web client port; reusing a tagged machine to administer another node; ACL changes that accidentally expose the web client port to tag groups.","solutions":["Access the web client from a user-owned (untagged) device belonging to the node owner","Tighten ACLs so tagged devices cannot reach the web client port (usually 5252)","If the machine must be untagged, remove its tags and re-register it as a user device"],"exampleFix":"# before\nacl grants tag:server -> web client port; curl from tagged node -> errTaggedRemoteSource\n\n# after\naccess the UI from your laptop (user-owned node) over its tailscale IP, or remove --advertise-tags from the source machine","handlingStrategy":"try-catch","validationCode":"// if you control the tailnet, keep tagged devices out of the web port in ACLs:\n// {\"action\": \"deny\", \"src\": [\"tag:server\"], \"dst\": [\"tag:web:5252\"]}","typeGuard":"func isTaggedSource(err error) bool {\n    return err != nil && (errors.Is(err, errTaggedRemoteSource) || errors.Is(err, errTaggedLocalSource))\n}","tryCatchPattern":"if _, _, _, err := s.getSession(r); err != nil {\n    switch {\n    case errors.Is(err, errTaggedRemoteSource):\n        http.Error(w, \"tagged nodes cannot use the web client; connect from a user-owned device\", http.StatusForbidden)\n    case err != nil:\n        // other cases\n    }\n}","preventionTips":["Administer nodes from user-owned devices, not tagged machines","Write ACLs so tag groups cannot reach web client ports","Document which identities (user vs machine) are valid web-client sources for your team"],"tags":["go","tailscale","web-client","authorization","tagged-nodes"],"backgroundTag":"tagged-node-access-denied","analyzedSha":"6e0912f97994f927632b34ae9e63b53d6516a6ac","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}