{"record":{"id":"431bdb36074b8e6d","repo":"koala73/worldmonitor","slug":"authentication-unavailable-while-loading-embed-keys-try","errorCode":null,"errorMessage":"Authentication unavailable while loading embed keys. Try again.","messagePattern":"Authentication unavailable while loading embed keys\\. Try again\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/embed-keys.ts","lineNumber":117,"sourceCode":"      (api as any).embedKeys.createEmbedKey,\n      { name: name.trim(), keyPrefix, keyHash },\n    ),\n  );\n  assertAccountStillCurrent(userId, 'creating the embed key');\n\n  return { id: result.id, name: result.name, keyPrefix: result.keyPrefix, key: plaintext };\n}\n\n/** List all embed keys for the current user. */\nexport async function listEmbedKeys(): Promise<EmbedKeyInfo[]> {\n  const userId = getCurrentClerkUser()?.id;\n  if (!userId) return [];\n\n  const [client, api] = await Promise.all([getConvexClient(), getConvexApi()]);\n  if (!client || !api) return [];\n  if (!await waitForConvexAuthForUser(userId)) {\n    assertAccountStillCurrent(userId, 'loading embed keys');\n    throw new Error('Authentication unavailable while loading embed keys. Try again.');\n  }\n\n  return settleAccountOperation(\n    userId,\n    'loading embed keys',\n    () => client.query((api as any).embedKeys.listEmbedKeys, {}),\n  );\n}\n\n/**\n * Revoke an embed key by its Convex document ID.\n *\n * Unlike `revokeApiKey`, this does not bust the edge validation cache: there is\n * no ownership-checked invalidation route for `embedKeys` yet, so a revoked key\n * keeps validating for at most the 60s `CACHE_TTL_SECONDS` in\n * `server/_shared/embed-key.ts`.\n *\n * A map frame is slower still: it already holds a `wmg_` grant good for up to","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/src/services/embed-keys.ts#L99-L135","documentation":"listEmbedKeys() returns [] when signed out but throws this when the user is signed in yet Clerk/Convex auth never becomes ready within the wait window (waitForConvexAuthForUser(userId) resolved false). It signals a transient auth-hydration stall rather than a data problem; assertAccountStillCurrent runs first so an account switch throws its own message instead.","triggerScenarios":"Calling listEmbedKeys() while the Clerk session/Convex token is still initializing, or when waitForConvexAuthForUser times out because Convex auth never completes for the current userId.","commonSituations":"Opening the embed-keys settings panel immediately after a page load or sign-in; slow network delaying the Convex auth handshake; a stale session rehydrating; switching accounts mid-load so the awaited user no longer matches.","solutions":["Retry the call after a short delay; the error message itself says 'Try again' and the condition is usually transient","Ensure the component only calls listEmbedKeys() after Clerk/Convex auth is confirmed ready (await an auth-ready hook/gate) instead of on mount","Check network connectivity and Convex deployment availability; a blocked Convex websocket keeps auth pending","If persistent, sign out and back in to reset the Clerk session and Convex auth client"],"exampleFix":"// before\nconst keys = await listEmbedKeys();\n// after\nlet keys;\ntry {\n  keys = await listEmbedKeys();\n} catch (e) {\n  if (e.message.includes('Authentication unavailable')) {\n    keys = await retry(listEmbedKeys, { retries: 3, delayMs: 500 });\n  } else throw e;\n}","handlingStrategy":"retry","validationCode":"if (!getCurrentClerkUser()) return []; // signed out: listEmbedKeys returns [] anyway","typeGuard":null,"tryCatchPattern":"try { keys = await listEmbedKeys(); } catch (e) { if (/Authentication unavailable/.test(e.message)) { await authReady(); keys = await listEmbedKeys(); } else throw e; }","preventionTips":["Gate settings panels on auth readiness (Clerk loaded + Convex authed) before fetching","Add bounded retry with backoff for auth-dependent reads","Avoid switching accounts while loads are in flight"],"tags":["authentication","convex","clerk","transient"],"backgroundTag":"authentication-required","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}