{"record":{"id":"dc393a8f23ac7937","repo":"kriasoft/react-starter-kit","slug":"unauthorized","errorCode":"UNAUTHORIZED","errorMessage":"Authentication required","messagePattern":"Authentication required","errorType":"error_code","errorClass":"TRPCError","httpStatus":401,"severity":"error","filePath":"apps/api/lib/trpc.ts","lineNumber":55,"sourceCode":"        TContext,\n        TMeta,\n        {\n          session: NonNullable<TRPCContext[\"session\"]>;\n          user: NonNullable<TRPCContext[\"user\"]>;\n        },\n        TInputIn,\n        TInputOut,\n        TOutputIn,\n        TOutputOut,\n        TCaller\n      >\n    : never;\n\nexport const protectedProcedure: ProtectedProcedure = t.procedure.use(\n  ({ ctx, next }) => {\n    if (!ctx.session || !ctx.user) {\n      throw new TRPCError({\n        code: \"UNAUTHORIZED\",\n        message: \"Authentication required\",\n      });\n    }\n    return next({\n      ctx: {\n        ...ctx,\n        session: ctx.session,\n        user: ctx.user,\n      },\n    });\n  },\n);\n","sourceCodeStart":37,"sourceCodeEnd":68,"githubUrl":"https://github.com/kriasoft/react-starter-kit/blob/0aa7603435f16159ad0b8fef68fb7f6280be7ca1/apps/api/lib/trpc.ts#L37-L68","documentation":"protectedProcedure is tRPC middleware that requires an authenticated session. When ctx.session or ctx.user is null it throws a TRPCError with code UNAUTHORIZED before the procedure body runs, and narrows the context types so downstream code can use ctx.user safely. It is the standard tRPC pattern for guarding private procedures.","triggerScenarios":"Calling any mutation/query built on protectedProcedure without a valid session cookie/Bearer token, with an expired session, or from a client that never forwarded credentials (e.g. missing credentials: 'include' on fetch).","commonSituations":"User's session expired while a tab stayed open, Better Auth cookie not sent cross-origin (wrong credentials mode or cookie domain), API client hitting the API worker directly without the auth header, or tests creating a caller without seeding a session.","solutions":["Sign in first (Better Auth sign-in flow) and ensure the session cookie/token is attached to subsequent requests","Check the client sends credentials: fetch('/api/trpc/...', { credentials: 'include' }) or the appropriate Authorization header","Verify cookie domain/SameSite settings allow the cookie on the API origin, especially in cross-worker routing setups","Handle the UNAUTHORIZED code on the client by redirecting to login instead of showing a raw error"],"exampleFix":"// before\nconst data = await trpc.billing.subscription.query(); // no session attached\n// after\nawait authClient.signIn.email({ email, password });\nconst data = await trpc.billing.subscription.query(undefined, { context: { credentials: 'include' } });","handlingStrategy":"try-catch","validationCode":"// client-side pre-check before calling a protected procedure\nconst { data: session } = await authClient.useSession();\nif (!session) {\n  redirect('/login?next=' + encodeURIComponent(currentPath));\n}","typeGuard":"function isUnauthorized(error: unknown): error is { code: 'UNAUTHORIZED'; message: string } {\n  return (\n    typeof error === 'object' && error !== null &&\n    'code' in error && (error as { code?: string }).code === 'UNAUTHORIZED'\n  );\n}","tryCatchPattern":"try {\n  return await trpc.billing.subscription.query();\n} catch (error) {\n  if (isTRPCClientError(error) && error.data?.code === 'UNAUTHORIZED') {\n    await authClient.signOut();\n    window.location.href = '/login';\n    return;\n  }\n  throw error;\n}","preventionTips":["Always attach credentials (cookies) to tRPC fetches; use credentials: 'include' cross-origin","Proactively check session validity before rendering authenticated UI and refresh expiring sessions","Catch UNAUTHORIZED globally in a tRPC link/middleware and redirect to login once, not per-call","In tests, seed a session via the auth test helpers before using createCallerFactory"],"tags":["trpc","auth","unauthorized","session"],"backgroundTag":"authentication-required","analyzedSha":"0aa7603435f16159ad0b8fef68fb7f6280be7ca1","analyzedAt":"2026-08-31T21:50:55.742Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}