{"record":{"id":"c41197fa58ed143b","repo":"mastra-ai/mastra","slug":"authenticated-user-is-missing-a-user-id","errorCode":null,"errorMessage":"Authenticated user is missing a user id","messagePattern":"Authenticated user is missing a user id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory-ui/src/ui/domains/auth/services/auth.ts","lineNumber":32,"sourceCode":" * different port still reaches the Mastra server — same pattern as the shared\n * API client and `use-fs`.\n */\n\nexport interface FactoryAuthState {\n  /** Whether the server has web auth configured (any provider). */\n  authEnabled: boolean;\n  authenticated: boolean;\n  user?: { userId?: string; email?: string; name?: string; avatarUrl?: string; organizationId?: string };\n  /** Active identity provider: 'workos' | 'better-auth' | custom adapter kind. */\n  provider?: string;\n  /** True when the provider hosts credential forms and sign-up is disabled. */\n  signUpDisabled?: boolean;\n}\n\n/** The resourceId under which a user's personal (non-factory) sessions live. */\nexport function userSessionResourceId(state: FactoryAuthState | undefined): string {\n  const userId = state?.user?.userId;\n  if (!userId) throw new Error('Authenticated user is missing a user id');\n  return userId;\n}\n\n/**\n * Build the hosted-login URL. `returnTo` is where the server sends the user\n * after authenticating; it defaults to the current location so contexts that\n * are not `/signin` (which would loop back to itself) round-trip in place.\n */\nexport function loginUrl(\n  baseUrl: string,\n  returnTo: string = window.location.pathname + window.location.search,\n): string {\n  return `${baseUrl}/auth/login?returnTo=${encodeURIComponent(returnTo)}`;\n}\n\n/** Full-page navigation to the hosted login (see `loginUrl` for `returnTo`). */\nexport function redirectToLogin(baseUrl: string, returnTo?: string): void {\n  window.location.assign(loginUrl(baseUrl, returnTo));","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory-ui/src/ui/domains/auth/services/auth.ts#L14-L50","documentation":"userSessionResourceId extracts the authenticated user's id from FactoryAuthState and uses it as the resourceId under which personal (non-factory) sessions live. It throws 'Authenticated user is missing a user id' when the state says a user is present but the userId field is absent (or state is undefined where a user was assumed), since session storage cannot be scoped without an id.","triggerScenarios":"Calling userSessionResourceId with state undefined (auth not yet loaded), or with a user object lacking userId — e.g. the auth endpoint returned a user payload without an id, or it is called before fetchAuthState resolves.","commonSituations":"Calling the helper during app boot before the auth check completes; a server-side change/upgrade altering the auth payload shape so userId is no longer populated; custom auth providers that omit userId; race conditions where session listing runs before authentication finishes.","solutions":["Only call userSessionResourceId after the auth state is loaded and authenticated, e.g. gate on state?.authenticated.","Check the /auth state payload actually includes user.userId; fix the auth provider/endpoint if it is missing.","Fall back to a loading state for personal-session UI until a userId is available.","If using a custom auth integration, map the provider's subject/id into user.userId."],"exampleFix":"// before\nconst resourceId = userSessionResourceId(authState); // throws if userId missing\n\n// after\nconst resourceId = authState?.user?.userId\n  ? userSessionResourceId(authState)\n  : null; // render loading/sign-in UI instead","handlingStrategy":"type-guard","validationCode":"if (!authState?.authenticated) return; // wait for auth to load before reading resourceId","typeGuard":"function hasUserId(state: FactoryAuthState | undefined): state is FactoryAuthState & { user: { userId: string } } {\n  return typeof state?.user?.userId === 'string' && state.user.userId.length > 0;\n}","tryCatchPattern":"let resourceId: string;\ntry {\n  resourceId = userSessionResourceId(authState);\n} catch {\n  return <SignInPrompt />; // or loading spinner while auth state resolves\n}","preventionTips":["Only call userSessionResourceId after the auth query resolves with authenticated: true.","Verify the auth provider maps its subject into user.userId.","Add a snapshot test asserting the auth payload includes userId."],"tags":["auth","authentication","missing-field","session"],"backgroundTag":"authenticated-user-missing-id","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}