Dokploy/dokploy · error · TRPCError
UNAUTHORIZED
UNAUTHORIZED
Error message
You are not authorized to access this server
What it means
Access-control check in the swarm 'nodes' query: when a serverId is supplied, the server row is looked up and its organizationId must equal the caller session's activeOrganizationId. Otherwise UNAUTHORIZED is thrown before getSwarmNodes runs. This prevents querying Docker swarm nodes on a server belonging to a different organization.
Source
Thrown at apps/dokploy/server/api/routers/swarm.ts:25
getSwarmNodes,
} from "@dokploy/server";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { createTRPCRouter, withPermission } from "../trpc";
import { containerIdRegex } from "./docker";
export const swarmRouter = createTRPCRouter({
getNodes: withPermission("docker", "read")
.input(
z.object({
serverId: z.string().optional(),
}),
)
.query(async ({ input, ctx }) => {
if (input.serverId) {
const server = await findServerById(input.serverId);
if (server.organizationId !== ctx.session?.activeOrganizationId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this server",
});
}
}
return await getSwarmNodes(input.serverId);
}),
getNodeInfo: withPermission("docker", "read")
.input(z.object({ nodeId: z.string(), serverId: z.string().optional() }))
.query(async ({ input, ctx }) => {
if (input.serverId) {
const server = await findServerById(input.serverId);
if (server.organizationId !== ctx.session?.activeOrganizationId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this server",
});
}View on GitHub (pinned to 546686ea35)
Solutions
- Switch the active organization in the UI to the one that owns the server, then retry
- Verify the serverId belongs to your current organization (check the servers list for that org)
- If the session org data is stale, log out and back in / refresh the session
Example fix
// before
const nodes = await api.swarm.nodes({ serverId });
// after
const server = await api.server.byId(serverId); // 404s if other-org/invisible
const nodes = await api.swarm.nodes({ serverId });
// better: omit serverId to target the current org's default server Defensive patterns
Strategy: validation
Validate before calling
const servers = await api.server.all(); // org-scoped
if (servers.some(s => s.serverId === serverId)) {
const nodes = await api.swarm.nodes({ serverId });
} Type guard
const serverInActiveOrg = (
servers: { serverId: string }[], id: string
) => servers.some(s => s.serverId === id); Try / catch
try { await api.swarm.nodes({ serverId }); }
catch (e) { if (e.shape?.data?.code === 'UNAUTHORIZED') promptOrgSwitch(); else throw e; } Prevention
- Always derive serverId from the active organization's server list
- Switch active organization before issuing server-scoped calls
- Never hardcode serverIds across environments
When it happens
Trigger: Calling swarm.nodes({ serverId }) where the server's organizationId differs from ctx.session.activeOrganizationId — e.g. a member of org A passing a serverId owned by org B, or the session's active organization not switched to the one owning the server.
Common situations: User belongs to multiple organizations and their active organization is the wrong one; stale client state after being moved between orgs; copying a serverId from another workspace's URL; deleted/re-created server rows with mismatched org ids.
Related errors
AI-assisted analysis of Dokploy/dokploy@546686ea35 (2026-08-27).
Data as JSON: /api/errors/f180608fa9afb4da.
Report an issue: GitHub.