{"record":{"id":"c78c56fd90519047","repo":"Dokploy/dokploy","slug":"unauthorized-c78c56","errorCode":"UNAUTHORIZED","errorMessage":"You are not authorized to update this notification","messagePattern":"You are not authorized to update this notification","errorType":"exception","errorClass":"TRPCError","httpStatus":401,"severity":"error","filePath":"apps/dokploy/server/api/routers/notification.ts","lineNumber":109,"sourceCode":"\tapiUpdateTelegram,\n\tnotifications,\n\tserver,\n} from \"@/server/db/schema\";\n\nexport const notificationRouter = createTRPCRouter({\n\tcreateSlack: withPermission(\"notification\", \"create\")\n\t\t.input(apiCreateSlack)\n\t\t.mutation(async ({ input, ctx }) => {\n\t\t\ttry {\n\t\t\t\tawait createSlackNotification(input, ctx.session.activeOrganizationId);\n\t\t\t\tawait audit(ctx, {\n\t\t\t\t\taction: \"create\",\n\t\t\t\t\tresourceType: \"notification\",\n\t\t\t\t\tresourceName: input.name,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.log(error);\n\t\t\t\tthrow new TRPCError({\n\t\t\t\t\tcode: \"BAD_REQUEST\",\n\t\t\t\t\tmessage: \"Error creating the notification\",\n\t\t\t\t\tcause: error,\n\t\t\t\t});\n\t\t\t}\n\t\t}),\n\tupdateSlack: withPermission(\"notification\", \"update\")\n\t\t.input(apiUpdateSlack)\n\t\t.mutation(async ({ input, ctx }) => {\n\t\t\ttry {\n\t\t\t\tconst notification = await findNotificationById(input.notificationId);\n\t\t\t\tif (notification.organizationId !== ctx.session.activeOrganizationId) {\n\t\t\t\t\tthrow new TRPCError({\n\t\t\t\t\t\tcode: \"UNAUTHORIZED\",\n\t\t\t\t\t\tmessage: \"You are not authorized to update this notification\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst result = await updateSlackNotification({","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/Dokploy/dokploy/blob/546686ea3587f12ec5652217dedd9f7960fb6d15/apps/dokploy/server/api/routers/notification.ts#L91-L127","documentation":"The updateSlack notification mutation throws UNAUTHORIZED when the notification's organizationId does not match the session's activeOrganizationId. It is wrapped in a try/catch whose catch-all rethrows unexpected errors as BAD_REQUEST, but this ownership check deliberately throws UNAUTHORIZED to block cross-organization edits of Slack notification channels.","triggerScenarios":"Calling notification.updateSlack with a notificationId belonging to another organization while withPermission(\"notification\",\"update\") has already authorized the permission level but the org-scoped ownership check fails.","commonSituations":"Stale notificationId in the edit form after switching organizations; importing/migrating notifications between Dokploy instances where IDs don't line up; automated scripts using hardcoded IDs.","solutions":["Switch the active organization to the one owning the notification and retry","Re-fetch the notifications list in the current org to obtain a valid notificationId","Confirm the notification still exists (a mismatched or deleted ID often surfaces this way)","Audit the notification in the owning org if cross-org access is genuinely needed"],"exampleFix":"// before\nawait trpc.notification.updateSlack.mutate({ notificationId: oldId, ...patch });\n// after\nconst list = await trpc.notification.all.query();\nconst target = list.find(n => n.notificationId === oldId);\nif (target?.organizationId === session.activeOrganizationId) {\n  await trpc.notification.updateSlack.mutate({ notificationId: oldId, ...patch });\n} else {\n  throw new Error('Switch organization or pick a notification you own');\n}","handlingStrategy":"validation","validationCode":"const list = await trpc.notification.all.query();\nconst mine = list.find(n => n.notificationId === id);\nif (!mine) throw new Error('Notification not accessible in active org');","typeGuard":"const isOwnedNotification = (n: {organizationId: string}, activeOrgId: string) =>\n  n.organizationId === activeOrgId;","tryCatchPattern":"catch (e) { if (e?.code === 'UNAUTHORIZED') showOrgSwitchHint(); else throw e; }","preventionTips":["Clear edit-form state when the active organization changes","Scope notification pickers to data from notification.all of the current session"],"tags":["dokploy","trpc","authorization","notifications","slack"],"backgroundTag":"cross-tenant-resource-authorization","analyzedSha":"546686ea3587f12ec5652217dedd9f7960fb6d15","analyzedAt":"2026-08-27T05:18:58.095Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}