{"record":{"id":"94de13aac6d69ae0","repo":"koala73/worldmonitor","slug":"sign-in-to-create-an-embed-key","errorCode":null,"errorMessage":"Sign in to create an embed key.","messagePattern":"Sign in to create an embed key\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/embed-keys.ts","lineNumber":83,"sourceCode":"/**\n * The display prefix stored alongside the hash.\n *\n * Nine characters — `wme_` plus five hex — because Convex validates it against\n * `/^wme_[a-f0-9]{5}$/`. `api-keys.ts` slices eight for `wm_` + five; the\n * longer scheme prefix is the whole difference, so this cannot be shared as a\n * constant without one of the two silently taking the other's length.\n */\nfunction embedKeyPrefix(plaintext: string): string {\n  return plaintext.slice(0, 9);\n}\n\n/**\n * Create a new embed key for the current user.\n * Returns the full plaintext key (shown once) and metadata.\n */\nexport async function createEmbedKey(name: string): Promise<CreateEmbedKeyResult> {\n  const userId = getCurrentClerkUser()?.id;\n  if (!userId) throw new Error('Sign in to create an embed key.');\n\n  const plaintext = generateEmbedKey();\n  const keyPrefix = embedKeyPrefix(plaintext);\n  const keyHash = await sha256Hex(plaintext);\n\n  const [client, api] = await Promise.all([getConvexClient(), getConvexApi()]);\n  if (!client || !api) throw new Error('Convex unavailable');\n  if (!await waitForConvexAuthForUser(userId)) {\n    throw new Error('Account changed while creating the embed key. Try again.');\n  }\n\n  const result = await settleAccountOperation(\n    userId,\n    'creating the embed key',\n    () => client.mutation(\n      (api as any).embedKeys.createEmbedKey,\n      { name: name.trim(), keyPrefix, keyHash },\n    ),","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/src/services/embed-keys.ts#L65-L101","documentation":"createEmbedKey requires an authenticated Clerk user; it reads getCurrentClerkUser()?.id and throws this error when there is none. The key creation flow (generate plaintext, hash, Convex mutation) is always scoped to a user, so an anonymous session cannot proceed.","triggerScenarios":"Calling createEmbedKey(name) while the user is signed out, the Clerk session has not yet loaded (user is null), or the Clerk provider failed to initialize so no user id is available.","commonSituations":"Embed-key UI reachable before Clerk finishes loading its session; user's session expired and was silently signed out; embedding the app without the Clerk provider configured; calling createEmbedKey from code that runs before auth hydration.","solutions":["Sign in via Clerk before attempting to create an embed key.","Gate the embed-key creation UI on the Clerk auth state (show a sign-in prompt until isSignedIn).","Await Clerk session hydration (useUser/isLoaded equivalent) before invoking createEmbedKey.","Verify the Clerk provider wraps the component so getCurrentClerkUser() can resolve."],"exampleFix":"// before\nawait createEmbedKey(name);\n// after\nconst { isSignedIn, isLoaded } = useClerkUser();\nif (!isLoaded) return; // wait for hydration\nif (!isSignedIn) { showSignInPrompt(); return; }\nawait createEmbedKey(name);","handlingStrategy":"validation","validationCode":"const userId = getCurrentClerkUser()?.id;\nif (!userId) { showSignInPrompt(); return; }\nawait createEmbedKey(name);","typeGuard":"const isSignedIn = (): boolean => typeof getCurrentClerkUser()?.id === 'string';","tryCatchPattern":"try {\n  await createEmbedKey(name);\n} catch (e) {\n  if (e.message === 'Sign in to create an embed key.') showSignInModal();\n  else throw e;\n}","preventionTips":["Gate key-management UI on Clerk isSignedIn and isLoaded.","Await Clerk session hydration before offering create actions.","Ensure the Clerk provider wraps the whole app."],"tags":["authentication","clerk","embed-keys"],"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"}