{"record":{"id":"ccc12ab01222c2e2","repo":"BloopAI/vibe-kanban","slug":"session-refresh-failed-please-sign-in-again","errorCode":null,"errorMessage":"Session refresh failed. Please sign in again.","messagePattern":"Session refresh failed\\. Please sign in again\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/remote-web/src/shared/lib/auth/tokenManager.ts","lineNumber":84,"sourceCode":"  if (refreshPromise) return refreshPromise;\n\n  const innerPromise =\n    typeof navigator.locks?.request === \"function\"\n      ? navigator.locks\n          .request(\"rf-token-refresh\", doTokenRefresh)\n          .then((t) => t)\n      : doTokenRefresh();\n\n  const promise = innerPromise\n    .catch(async (error: unknown) => {\n      await clearTokens();\n\n      const status = (error as { status?: number }).status;\n      if (status === 401) {\n        throw new Error(\"Session expired. Please sign in again.\");\n      }\n\n      throw new Error(\"Session refresh failed. Please sign in again.\");\n    })\n    .finally(() => {\n      refreshPromise = null;\n    });\n\n  refreshPromise = promise;\n  return promise;\n}\n\nexport async function getToken(): Promise<string> {\n  const accessToken = await getAccessToken();\n  if (!accessToken) {\n    if (!(await getRefreshToken())) throw new Error(\"Not authenticated\");\n    return handleTokenRefresh();\n  }\n  if (shouldRefreshAccessToken(accessToken)) return handleTokenRefresh();\n  return accessToken;\n}","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/packages/remote-web/src/shared/lib/auth/tokenManager.ts#L66-L102","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\nconst promise = innerPromise.catch(async (error) => { await clearTokens(); throw new Error('Session refresh failed...'); });\n// after\nconst promise = innerPromise.catch(async (error) => {\n  const status = (error as { status?: number }).status;\n  if (status && status >= 500) { /* schedule a retry instead of clearing tokens */ }\n  await clearTokens();\n  throw new Error(status === 401 ? 'Session expired...' : 'Session refresh failed...');\n});","handlingStrategy":"retry","validationCode":"async function isAuthServerReachable(url: string): Promise<boolean> {\n  try { const r = await fetch(url, { method: 'HEAD' }); return r.status < 500; }\n  catch { return false; }\n}","typeGuard":"function isTransientRefreshError(e: unknown): boolean {\n  const status = (e as { status?: number })?.status;\n  return status === undefined || status >= 500;\n}","tryCatchPattern":"try {\n  const token = await getToken();\n} catch (e) {\n  if (isTransientRefreshError(e)) {\n    await backoff(() => getToken(), 3);\n  } else {\n    redirectToLogin({ reason: 'refresh_failed' });\n  }\n}","preventionTips":["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."],"tags":["auth","token-refresh","network","transient-failure"],"backgroundTag":"token-refresh-failed","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}