{"record":{"id":"099257c5dc89688c","repo":"BloopAI/vibe-kanban","slug":"not-authenticated-099257","errorCode":null,"errorMessage":"Not authenticated","messagePattern":"Not authenticated","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/web-core/src/shared/lib/remoteApi.ts","lineNumber":64,"sourceCode":"\nexport const makeRequest = async (\n  path: string,\n  options: RequestInit = {},\n  retryOn401 = true\n): Promise<Response> => {\n  return makeAuthenticatedRequest(getRemoteApiUrl(), path, options, retryOn401);\n};\n\nasync function makeAuthenticatedRequest(\n  baseUrl: string,\n  path: string,\n  options: RequestInit = {},\n  retryOn401 = true\n): Promise<Response> {\n  const authRuntime = getAuthRuntime();\n  const token = await authRuntime.getToken();\n  if (!token) {\n    throw new Error('Not authenticated');\n  }\n\n  const headers = new Headers(options.headers ?? {});\n  if (!headers.has('Content-Type')) {\n    headers.set('Content-Type', 'application/json');\n  }\n  headers.set('Authorization', `Bearer ${token}`);\n  headers.set('X-Client-Version', __APP_VERSION__);\n  headers.set('X-Client-Type', 'frontend');\n\n  const response = await fetch(`${baseUrl}${path}`, {\n    ...options,\n    headers,\n    credentials: 'include',\n  });\n\n  // Handle 401 - token may have expired\n  if (response.status === 401 && retryOn401) {","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/packages/web-core/src/shared/lib/remoteApi.ts#L46-L82","documentation":"makeAuthenticatedRequest in remoteApi.ts throws 'Not authenticated' when authRuntime.getToken() resolves to null/undefined — there is no access token available at all, so no request is attempted. Unlike the 401 path, this fires before any network call.","triggerScenarios":"Calling any remoteApi.makeRequest-wrapped function (projects, issues, attachments, relay hosts) while the user has never logged in, has logged out, or the token store hasn't been hydrated yet (e.g. call fired during app bootstrap before auth initialization completes).","commonSituations":"Making API calls before AuthProvider/ConfigProvider finish initializing; expired refresh token cleared from storage so getToken() returns null; direct calls in tests or scripts without setting up the auth runtime; deep-link into an authenticated page without a session.","solutions":["Gate authenticated API calls behind an isAuthenticated check from the auth runtime.","Await auth initialization (token hydration) before firing requests on app startup.","Redirect to login when no token is present instead of issuing the call.","In tests/scripts, initialize the auth runtime (or mock getAuthRuntime) before calling makeRequest."],"exampleFix":"// before\nconst projects = await listProjects(); // throws if token missing\n// after\nconst auth = getAuthRuntime();\nif (!(await auth.getToken())) {\n  redirectToLogin();\n  return;\n}\nconst projects = await listProjects();","handlingStrategy":"try-catch","validationCode":"const authRuntime = getAuthRuntime();\nconst token = await authRuntime.getToken();\nif (!token) {\n  redirectToLogin();\n  return; // don't call the API\n}","typeGuard":"function isNotAuthenticatedError(e: unknown): e is Error {\n  return e instanceof Error && e.message === 'Not authenticated';\n}","tryCatchPattern":"try {\n  const resp = await makeRequest('/v1/projects');\n} catch (e) {\n  if (isNotAuthenticatedError(e)) {\n    await authRuntime.logout();\n    window.location.assign('/login');\n    return;\n  }\n  throw e;\n}","preventionTips":["Initialize/hydrate the auth runtime before any authenticated fetch on app startup","Gate authenticated pages/components behind an auth guard","Treat 'Not authenticated' as a routing signal (go to login), not a retryable error","In tests, mock getAuthRuntime with a token before calling makeRequest"],"tags":["auth","unauthenticated","token"],"backgroundTag":"missing-auth-token","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}