{"record":{"id":"3e992e261097d94c","repo":"koala73/worldmonitor","slug":"not-authenticated","errorCode":null,"errorMessage":"Not authenticated","messagePattern":"Not authenticated","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/push-notifications.ts","lineNumber":110,"sourceCode":"    auth,\n    userAgent: typeof navigator !== 'undefined' ? navigator.userAgent.slice(0, 200) : '',\n  };\n}\n\nfunction assertExpectedAccount(expectedUserId?: string): void {\n  if (expectedUserId && getCurrentClerkUser()?.id !== expectedUserId) {\n    throw new Error('Authenticated account changed during push setup');\n  }\n}\n\nasync function authFetch(\n  path: string,\n  init: RequestInit,\n  expectedUserId?: string,\n): Promise<Response> {\n  assertExpectedAccount(expectedUserId);\n  const token = await getClerkToken();\n  if (!token) throw new Error('Not authenticated');\n  assertExpectedAccount(expectedUserId);\n  return fetch(path, {\n    ...init,\n    headers: {\n      'Content-Type': 'application/json',\n      ...(init.headers ?? {}),\n      Authorization: `Bearer ${token}`,\n    },\n  });\n}\n\n/**\n * Ask permission (if needed), subscribe via pushManager, and register\n * the endpoint with the server. Resolves with the payload the server\n * accepted, or throws on cancel / denial / network failure.\n */\nexport async function subscribeToPush(expectedUserId?: string): Promise<SubscriptionPayload> {\n  assertExpectedAccount(expectedUserId);","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/koala73/worldmonitor/blob/eeab0a219fce0f02a00603b532dbae9041b934ac/src/services/push-notifications.ts#L92-L128","documentation":"Thrown by authFetch() in src/services/push-notifications.ts when getClerkToken() resolves to null while trying to attach a Bearer header to a push-registration request. Clerk yields no token when there is no active session: the user is signed out, the session expired, or Clerk has not finished initializing. The fetch is never issued.","triggerScenarios":"Calling subscribeToPush/unsubscribeToPush (or any push endpoint call via authFetch) while signed out; after session expiry in a long-open tab; during the brief window before Clerk hydrates after page load; when Clerk JS failed to load so no session exists.","commonSituations":"Users leaving the dashboard open past the session TTL then enabling notifications; interacting with a push toggle rendered before Clerk finished loading; browser extensions or networks blocking Clerk's script.","solutions":["Re-authenticate (open Clerk sign-in) and retry the push setup.","Gate push UI behind a signed-in check (getCurrentClerkUser()) so unauthenticated users never reach the fetch.","Ensure Clerk is fully loaded before mounting push controls (await Clerk's loaded state).","Treat this message as 'sign in required' UX copy, not a generic failure."],"exampleFix":"// before\nawait subscribeToPush(userId);\n\n// after\nimport { getCurrentClerkUser } from '@/services/clerk';\nif (!getCurrentClerkUser()) {\n  await clerkOpenSignIn();\n  return;\n}\nawait subscribeToPush(userId);","handlingStrategy":"validation","validationCode":"import { getCurrentClerkUser } from '@/services/clerk';\n\nif (!getCurrentClerkUser()) {\n  await openClerkSignIn();\n  return;\n}\nawait subscribeToPush(expectedUserId);","typeGuard":"function isNotAuthenticated(err: unknown): boolean {\n  return err instanceof Error && err.message === 'Not authenticated';\n}","tryCatchPattern":"try {\n  await subscribeToPush(expectedUserId);\n} catch (err) {\n  if (isNotAuthenticated(err)) {\n    await openClerkSignIn(); // session needed before push registration can continue\n    return;\n  }\n  throw err;\n}","preventionTips":["Gate push controls behind a live signed-in check and Clerk's loaded state.","Handle Clerk session-expiry globally so long-idle tabs re-authenticate before user actions.","Map this message to 'sign in required' UX copy rather than a generic error."],"tags":["clerk","authentication","push-notifications","session-expired"],"backgroundTag":"missing-auth-token","analyzedSha":"eeab0a219fce0f02a00603b532dbae9041b934ac","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}