tailscale/tailscale · info

errNoSession

errNoSession

Error message

no-browser-session

What it means

errNoSession is a sentinel error from the Tailscale web client (client/web/auth.go) meaning the request carries no usable browser session. getSession returns it when the request has no session cookie at all, when the cookie value is not in the in-memory browserSessions map, when the session was created by a different node/user, or when the session expired (30 days by default). It is the normal 'not logged in yet' signal that drives the web client to its login flow.

Source

Thrown at client/web/auth.go:76

	case s.isExpired(now):
		return false // expired
	}
	return true
}

// isExpired reports true if s is expired.
// 2023-10-05: Sessions expire by default 30 days after creation.
func (s *browserSession) isExpired(now time.Time) bool {
	return !s.Created.IsZero() && now.After(s.expires())
}

// expires reports when the given session expires.
func (s *browserSession) expires() time.Time {
	return s.Created.Add(sessionCookieExpiry)
}

var (
	errNoSession          = errors.New("no-browser-session")
	errNotUsingTailscale  = errors.New("not-using-tailscale")
	errTaggedRemoteSource = errors.New("tagged-remote-source")
	errTaggedLocalSource  = errors.New("tagged-local-source")
	errNotOwner           = errors.New("not-owner")
)

// getSession retrieves the browser session associated with the request,
// if one exists.
//
// An error is returned in any of the following cases:
//
//   - (errNotUsingTailscale) The request was not made over tailscale.
//
//   - (errNoSession) The request does not have a session.
//
//   - (errTaggedRemoteSource) The source is remote (another node) and tagged.
//     Users must use their own user-owned devices to manage other nodes'
//     web clients.

View on GitHub (pinned to 6e0912f979)

Solutions

  1. Complete the web client login flow to obtain a fresh session cookie before calling protected endpoints
  2. Ensure every request sends the session cookie (same browser profile, credentials: 'include' for fetch/XHR)
  3. If the web client process restarted, log in again - sessions are in-memory only
  4. If the node was re-logged-in as a different identity, log in again so the session is re-bound to the current node/user

Example fix

// before
http.HandleFunc("/api/", s.authed(func(w, r) {...})) // 500 on first visit

// after
http.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) {
	_, _, _, err := s.getSession(r)
	if errors.Is(err, errNoSession) {
		http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
		return
	}
	// proceed
})
Defensive patterns

Strategy: try-catch

Validate before calling

// before hitting protected web-client routes, check the cookie exists
if _, err := r.Cookie("tailscale-webclient-session"); errors.Is(err, http.ErrNoCookie) {
    http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
    return
}

Type guard

func isNoSession(err error) bool {
    return err != nil && errors.Is(err, errNoSession) // within package web; externally: err.Error() == "no-browser-session"
}

Try / catch

sess, whois, status, err := s.getSession(r)
switch {
case errors.Is(err, errNoSession):
    // expected state: send the user through the login flow, do not log as 5xx
    http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
    return
case err != nil:
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
}

Prevention

When it happens

Trigger: Calling a web client handler before completing the browser-based login; cookie deleted or not sent (different browser, incognito, cross-origin fetch without credentials); the tailscale/web client process restarted so the in-memory sync.Map session store is empty; the session hit sessionCookieExpiry; or the source node/user changed since login (machine logged out and back in as a different identity).

Common situations: First visit to the web UI; long-lived tab whose 30-day session expired; server restart wiping sessions while the browser still holds the cookie; automated clients that hit web client routes without ever performing the login handshake.

Related errors


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