Dokploy/dokploy · error · TRPCError
FORBIDDEN
FORBIDDEN
Error message
Only the organization owner can create an organization
What it means
Role guard on organization creation: on self-hosted instances only users with role 'owner' or 'admin' may create organizations. On cloud (IS_CLOUD) this branch is skipped in favor of license/plan checks handled right after. Hitting it means the authenticated user's role is below admin (e.g. 'member' or 'user').
Source
Thrown at apps/dokploy/server/api/routers/organization.ts:34
import {
invitation,
member,
organization,
organizationRole,
user,
} from "@/server/db/schema";
import { createTRPCRouter, protectedProcedure, withPermission } from "../trpc";
export const organizationRouter = createTRPCRouter({
create: protectedProcedure
.input(
z.object({
name: z.string(),
logo: z.string().optional(),
}),
)
.mutation(async ({ ctx, input }) => {
if (ctx.user.role !== "owner" && ctx.user.role !== "admin" && !IS_CLOUD) {
throw new TRPCError({
code: "FORBIDDEN",
message: "Only the organization owner can create an organization",
});
}
if (IS_CLOUD) {
await assertOrganizationLimit(ctx.user.id);
}
const result = await db
.insert(organization)
.values({
...input,
slug: nanoid(),
createdAt: new Date(),
ownerId: ctx.user.id,
})
.returning()View on GitHub (pinned to 546686ea35)
Solutions
- Have an owner/admin create the organization, or promote the user's role first
- Log out and back in if the user's role was recently elevated so the session reflects it
- Verify ctx.user.role in the session payload (JWT) matches what you expect
- If you are the owner and still blocked, check the users table role value
Example fix
// before: member user calls
await trpc.organization.create.mutate({ name: 'New Org' }); // FORBIDDEN
// after: as owner/admin, or elevate first
// UPDATE users SET role='admin' WHERE id='<user-id>'; -- then re-login
await trpc.organization.create.mutate({ name: 'New Org' }); Defensive patterns
Strategy: validation
Validate before calling
const me = await trpc.auth.me.query();
if (!['owner', 'admin'].includes(me.role)) throw new Error('Ask an admin to create the organization'); Type guard
const canCreateOrg = (u: { role: string }, isCloud: boolean) => isCloud || u.role === 'owner' || u.role === 'admin'; Try / catch
try { await create(input); } catch (e) { if (getTRPCCode(e) === 'FORBIDDEN') showUpsellOrAskAdmin(); else throw e; } Prevention
- Hide the 'New Organization' button for non-admin roles
- Re-login after role elevation
- Check session.role in devtools before debugging 403s
When it happens
Trigger: On a self-hosted Dokploy, a non-admin/non-owner user calls the organization.create mutation. The check is `ctx.user.role !== 'owner' && ctx.user.role !== 'admin' && !IS_CLOUD`.
Common situations: A team member who was invited to the instance tries to create their own organization; scripts authenticated with a lower-privilege user's session; role was changed after login but stale session role is used.
Related errors
AI-assisted analysis of Dokploy/dokploy@546686ea35 (2026-08-27).
Data as JSON: /api/errors/d88274884a4a3673.
Report an issue: GitHub.