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
- Log in again — this is the expected unauthenticated-state signal
- Check that your session cookie is present and not expired
- If you believe you are logged in, verify the frontend REMOTE points at the backend you authenticated against
- 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
- Guard protected routes with an auth check before deep links are shared
- Re-authenticate after long idle periods
- Verify the frontend points at the backend instance you authenticated against
- Clear stale workspace/user stores on logout
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
- Not logged in. Please run 'wmill workspace add' first.
- Not logged in. Please run 'wmill workspace add' first.
- Got an HTML response from ${url} (status ${status}${cfPart ?
- No workspace available
- errorText || 'Failed to authorize debug session'
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/6d1c7843db41b5b5.
Report an issue: GitHub.