{"record":{"id":"63119b607f77366c","repo":"Dokploy/dokploy","slug":"unauthorized-63119b","errorCode":"UNAUTHORIZED","errorMessage":"UNAUTHORIZED","messagePattern":"UNAUTHORIZED","errorType":"error_code","errorClass":"TRPCError","httpStatus":401,"severity":"error","filePath":"apps/dokploy/server/api/trpc.ts","lineNumber":163,"sourceCode":" * Public (unauthenticated) procedure\n *\n * This is the base piece you use to build new queries and mutations on your tRPC API. It does not\n * guarantee that a user querying is authorized, but you can still access user session data if they\n * are logged in.\n */\nexport const publicProcedure = t.procedure;\n\n/**\n * Protected (authenticated) procedure\n *\n * If you want a query or mutation to ONLY be accessible to logged in users, use this. It verifies\n * the session is valid and guarantees `ctx.session.user` is not null.\n *\n * @see https://trpc.io/docs/procedures\n */\nexport const protectedProcedure = t.procedure.use(({ ctx, next }) => {\n\tif (!ctx.session || !ctx.user) {\n\t\tthrow new TRPCError({ code: \"UNAUTHORIZED\" });\n\t}\n\treturn next({\n\t\tctx: {\n\t\t\t// infers the `session` as non-nullable\n\t\t\tsession: ctx.session,\n\t\t\tuser: ctx.user,\n\t\t\t// session: { ...ctx.session, user: ctx.user },\n\t\t},\n\t});\n});\n\nexport const cliProcedure = t.procedure.use(({ ctx, next }) => {\n\tif (\n\t\t!ctx.session ||\n\t\t!ctx.user ||\n\t\t(ctx.user.role !== \"owner\" && ctx.user.role !== \"admin\")\n\t) {\n\t\tthrow new TRPCError({ code: \"UNAUTHORIZED\" });","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/Dokploy/dokploy/blob/546686ea3587f12ec5652217dedd9f7960fb6d15/apps/dokploy/server/api/trpc.ts#L145-L181","documentation":"Base tRPC middleware (protectedProcedure) that rejects any request without a valid session and user on the context. Every protected procedure runs this check, so any unauthenticated call surfaces as a bare UNAUTHORIZED error with no message.","triggerScenarios":"Calling any protectedProcedure tRPC endpoint without a valid session cookie, with an expired session, or after the session was revoked server-side.","commonSituations":"Session cookie expired while the app was idle; auth cookie not sent due to cross-origin misconfiguration; server restarted with a new auth secret invalidating sessions; automated scripts calling tRPC endpoints without auth headers.","solutions":["Redirect the user to the login page when receiving UNAUTHORIZED from any tRPC call","Check that the auth cookie is included (credentials/sameSite settings) in cross-origin setups","Verify AUTH_SECRET / session storage env vars are stable across deployments","Re-authenticate and retry the request"],"exampleFix":"// before\nconst res = await client.project.all.query();\n// after\ntry { const res = await client.project.all.query(); }\ncatch (e) { if (e?.data?.code === 'UNAUTHORIZED') window.location.href = '/signin'; throw e; }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"const isTRPCUnauthorized = (e: unknown): boolean =>\n  typeof e === 'object' && e !== null && (e as any)?.data?.code === 'UNAUTHORIZED' && !(e as any)?.message;","tryCatchPattern":"try { await protectedCall(); } catch (e) { if (isTRPCUnauthorized(e)) { await signOut(); redirect('/signin'); } throw e; }","preventionTips":["Add a global tRPC error-link that redirects on UNAUTHORIZED","Keep auth secrets stable across deploys to avoid mass session invalidation","Include credentials on cross-origin tRPC clients"],"tags":["trpc","authentication","session","middleware"],"backgroundTag":"session-expired-unauthorized","analyzedSha":"546686ea3587f12ec5652217dedd9f7960fb6d15","analyzedAt":"2026-08-27T05:18:58.095Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}