Dokploy/dokploy · error · TRPCError

UNAUTHORIZED

UNAUTHORIZED

Error message

You are not authorized to update this notification

What it means

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.

Source

Thrown at apps/dokploy/server/api/routers/notification.ts:109

	apiUpdateTelegram,
	notifications,
	server,
} from "@/server/db/schema";

export const notificationRouter = createTRPCRouter({
	createSlack: withPermission("notification", "create")
		.input(apiCreateSlack)
		.mutation(async ({ input, ctx }) => {
			try {
				await createSlackNotification(input, ctx.session.activeOrganizationId);
				await audit(ctx, {
					action: "create",
					resourceType: "notification",
					resourceName: input.name,
				});
			} catch (error) {
				console.log(error);
				throw new TRPCError({
					code: "BAD_REQUEST",
					message: "Error creating the notification",
					cause: error,
				});
			}
		}),
	updateSlack: withPermission("notification", "update")
		.input(apiUpdateSlack)
		.mutation(async ({ input, ctx }) => {
			try {
				const notification = await findNotificationById(input.notificationId);
				if (notification.organizationId !== ctx.session.activeOrganizationId) {
					throw new TRPCError({
						code: "UNAUTHORIZED",
						message: "You are not authorized to update this notification",
					});
				}
				const result = await updateSlackNotification({

View on GitHub (pinned to 546686ea35)

Solutions

  1. Switch the active organization to the one owning the notification and retry
  2. Re-fetch the notifications list in the current org to obtain a valid notificationId
  3. Confirm the notification still exists (a mismatched or deleted ID often surfaces this way)
  4. Audit the notification in the owning org if cross-org access is genuinely needed

Example fix

// before
await trpc.notification.updateSlack.mutate({ notificationId: oldId, ...patch });
// after
const list = await trpc.notification.all.query();
const target = list.find(n => n.notificationId === oldId);
if (target?.organizationId === session.activeOrganizationId) {
  await trpc.notification.updateSlack.mutate({ notificationId: oldId, ...patch });
} else {
  throw new Error('Switch organization or pick a notification you own');
}
Defensive patterns

Strategy: validation

Validate before calling

const list = await trpc.notification.all.query();
const mine = list.find(n => n.notificationId === id);
if (!mine) throw new Error('Notification not accessible in active org');

Type guard

const isOwnedNotification = (n: {organizationId: string}, activeOrgId: string) =>
  n.organizationId === activeOrgId;

Try / catch

catch (e) { if (e?.code === 'UNAUTHORIZED') showOrgSwitchHint(); else throw e; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Dokploy/dokploy@546686ea35 (2026-08-27). Data as JSON: /api/errors/c78c56fd90519047. Report an issue: GitHub.