{"record":{"id":"f180608fa9afb4da","repo":"Dokploy/dokploy","slug":"unauthorized-f18060","errorCode":"UNAUTHORIZED","errorMessage":"You are not authorized to access this server","messagePattern":"You are not authorized to access this server","errorType":"exception","errorClass":"TRPCError","httpStatus":401,"severity":"error","filePath":"apps/dokploy/server/api/routers/swarm.ts","lineNumber":25,"sourceCode":"\tgetSwarmNodes,\n} from \"@dokploy/server\";\nimport { TRPCError } from \"@trpc/server\";\nimport { z } from \"zod\";\nimport { createTRPCRouter, withPermission } from \"../trpc\";\nimport { containerIdRegex } from \"./docker\";\n\nexport const swarmRouter = createTRPCRouter({\n\tgetNodes: withPermission(\"docker\", \"read\")\n\t\t.input(\n\t\t\tz.object({\n\t\t\t\tserverId: z.string().optional(),\n\t\t\t}),\n\t\t)\n\t\t.query(async ({ input, ctx }) => {\n\t\t\tif (input.serverId) {\n\t\t\t\tconst server = await findServerById(input.serverId);\n\t\t\t\tif (server.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 access this server\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn await getSwarmNodes(input.serverId);\n\t\t}),\n\tgetNodeInfo: withPermission(\"docker\", \"read\")\n\t\t.input(z.object({ nodeId: z.string(), serverId: z.string().optional() }))\n\t\t.query(async ({ input, ctx }) => {\n\t\t\tif (input.serverId) {\n\t\t\t\tconst server = await findServerById(input.serverId);\n\t\t\t\tif (server.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 access this server\",\n\t\t\t\t\t});\n\t\t\t\t}","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/Dokploy/dokploy/blob/546686ea3587f12ec5652217dedd9f7960fb6d15/apps/dokploy/server/api/routers/swarm.ts#L7-L43","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst nodes = await api.swarm.nodes({ serverId });\n// after\nconst server = await api.server.byId(serverId); // 404s if other-org/invisible\nconst nodes = await api.swarm.nodes({ serverId });\n// better: omit serverId to target the current org's default server","handlingStrategy":"validation","validationCode":"const servers = await api.server.all(); // org-scoped\nif (servers.some(s => s.serverId === serverId)) {\n  const nodes = await api.swarm.nodes({ serverId });\n}","typeGuard":"const serverInActiveOrg = (\n  servers: { serverId: string }[], id: string\n) => servers.some(s => s.serverId === id);","tryCatchPattern":"try { await api.swarm.nodes({ serverId }); }\ncatch (e) { if (e.shape?.data?.code === 'UNAUTHORIZED') promptOrgSwitch(); else throw e; }","preventionTips":["Always derive serverId from the active organization's server list","Switch active organization before issuing server-scoped calls","Never hardcode serverIds across environments"],"tags":["authorization","multi-tenant","swarm","dokploy","trpc"],"backgroundTag":"cross-organization-access-denied","analyzedSha":"546686ea3587f12ec5652217dedd9f7960fb6d15","analyzedAt":"2026-08-27T05:18:58.095Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}