windmill-labs/windmill · warning

Not logged in

Error message

Not logged in

What it means

In the root layout `loadUser`, after workspace resolution completes (and only if the active workspace has not switched away), a null user means there is no authenticated session, so the layout throws 'Not logged in' to redirect to login.

Source

Thrown at frontend/src/routes/(root)/+layout.svelte:143

			await refreshSuperadmin()

			if ($workspaceStore) {
				if (await tryRecoverFromDeletedWorkspace($workspaceStore)) {
					return
				}
				if ($userStore) {
					console.log(`Welcome back ${$userStore.username} to ${$workspaceStore}`)
				} else {
					const ws = $workspaceStore
					const user = await getUserExt(ws)
					// A switch mid-flight means this answers for the workspace we left, and
					// that switch has already started the fetch answering for the active
					// one: neither this role nor its failure describes where we are now.
					if ($workspaceStore !== ws) {
						return
					}
					if (!user) {
						throw Error('Not logged in')
					}
					$userStore = user
				}
			} else {
				if (
					(!page.url.pathname.startsWith('/user/') || page.url.pathname.startsWith('/user/cli')) &&
					!page.url.pathname.startsWith('/oauth/mcp_authorize') &&
					// The hub import wizard asks for the destination itself, and may end in a
					// workspace that does not exist yet — bouncing it to the picker would
					// force the very choice it exists to make.
					!page.url.pathname.startsWith(`${base}/projects/import`)
				) {
					goto(
						`/user/workspaces?rd=${encodeURIComponent(page.url.href.replace(page.url.origin, ''))}`
					)
				}
				let user = await UserService.globalWhoami()
				console.log(`Welcome back ${user.email}`)

View on GitHub (pinned to e474e8803c)

Solutions

  1. Log in again — this is the expected unauthenticated-state signal
  2. Check that your session cookie is present and not expired
  3. If you believe you are logged in, verify the frontend REMOTE points at the backend you authenticated against
  4. Clear stale state (logout fully) and re-authenticate

Example fix

// before: assume logged in
await goto('/');
// after: guard
try { await loadUser(); } catch (e) {
  if (String(e) === 'Error: Not logged in') await goto('/user/login');
  else throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before navigating to a protected route
const res = await fetch(`${backendUrl}/api/users/whoami`);
if (res.status === 401 || res.status === 403) await goto('/user/login');

Type guard

function isLoggedIn(user: unknown): user is { email: string; is_admin?: boolean } {
  return !!user && typeof (user as any).email === 'string';
}

Try / catch

try { await loadUser(); } catch (e) {
  if (/Not logged in/.test(String(e))) await goto('/user/login?redirect=' + encodeURIComponent(location.pathname));
  else throw e;
}

Prevention

When it happens

Trigger: Loading any protected route without a valid session cookie/token, after session expiry, after logout with a stale in-memory store, or when the /user/me-style fetch returns null for the current workspace context.

Common situations: Token expired after idle time, sharing a link directly without logging in, backend restarted without the session store, or the guard bailing because $workspaceStore changed mid-fetch leaving user null.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/6d1c7843db41b5b5. Report an issue: GitHub.