BloopAI/vibe-kanban · error · Error
Session refresh failed. Please sign in again.
Error message
Session refresh failed. Please sign in again.
What it means
tokenManager throws this when the token refresh call fails with any non-401 status (or a network/unknown error without a status), i.e. the session could not be refreshed but the server did not explicitly say the token is invalid. Tokens are cleared and refreshPromise is reset in finally so a later call can retry cleanly.
Source
Thrown at packages/remote-web/src/shared/lib/auth/tokenManager.ts:84
if (refreshPromise) return refreshPromise;
const innerPromise =
typeof navigator.locks?.request === "function"
? navigator.locks
.request("rf-token-refresh", doTokenRefresh)
.then((t) => t)
: doTokenRefresh();
const promise = innerPromise
.catch(async (error: unknown) => {
await clearTokens();
const status = (error as { status?: number }).status;
if (status === 401) {
throw new Error("Session expired. Please sign in again.");
}
throw new Error("Session refresh failed. Please sign in again.");
})
.finally(() => {
refreshPromise = null;
});
refreshPromise = promise;
return promise;
}
export async function getToken(): Promise<string> {
const accessToken = await getAccessToken();
if (!accessToken) {
if (!(await getRefreshToken())) throw new Error("Not authenticated");
return handleTokenRefresh();
}
if (shouldRefreshAccessToken(accessToken)) return handleTokenRefresh();
return accessToken;
}View on GitHub (pinned to 4deb7eca8f)
Solutions
- Retry the refresh once or twice with backoff for transient 5xx/network failures before clearing tokens.
- Check the auth server's health/logs for the corresponding failed request.
- Verify the refresh endpoint URL, CORS headers, and proxy configuration.
- Redirect to sign-in if retries also fail (tokens are already cleared).
Example fix
// before
const promise = innerPromise.catch(async (error) => { await clearTokens(); throw new Error('Session refresh failed...'); });
// after
const promise = innerPromise.catch(async (error) => {
const status = (error as { status?: number }).status;
if (status && status >= 500) { /* schedule a retry instead of clearing tokens */ }
await clearTokens();
throw new Error(status === 401 ? 'Session expired...' : 'Session refresh failed...');
}); Defensive patterns
Strategy: retry
Validate before calling
async function isAuthServerReachable(url: string): Promise<boolean> {
try { const r = await fetch(url, { method: 'HEAD' }); return r.status < 500; }
catch { return false; }
} Type guard
function isTransientRefreshError(e: unknown): boolean {
const status = (e as { status?: number })?.status;
return status === undefined || status >= 500;
} Try / catch
try {
const token = await getToken();
} catch (e) {
if (isTransientRefreshError(e)) {
await backoff(() => getToken(), 3);
} else {
redirectToLogin({ reason: 'refresh_failed' });
}
} Prevention
- Add exponential-backoff retries for 5xx/network refresh failures before clearing tokens.
- Monitor auth server health and deploy behind redundant infrastructure.
- Distinguish 401 (re-auth) from other statuses (retry) in your error handling.
When it happens
Trigger: getToken()/triggerRefresh() -> handleTokenRefresh; the refresh request rejects or resolves with a status other than 401 (500, 502, 503, timeout, TypeError from fetch) — the catch falls through the 401 check and throws this message.
Common situations: Auth server temporarily down or behind a failing proxy/load balancer; CORS misconfiguration on the refresh endpoint; DNS/network outage on the client; intermittent 5xx during deployments.
Related errors
- Host returned HTTP ${response.status}
- Auth methods lookup failed (${res.status})
- Failed to accept invitation (${res.status})
- Failed to list organizations (${res.status})
- Failed to fetch identity (${res.status})
AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29).
Data as JSON: /api/errors/ccc12ab01222c2e2.
Report an issue: GitHub.