{"record":{"id":"d73669e6fe952c94","repo":"Dokploy/dokploy","slug":"unauthorized-d73669","errorCode":"UNAUTHORIZED","errorMessage":"You are not allowed to access this destination","messagePattern":"You are not allowed to access this destination","errorType":"exception","errorClass":"TRPCError","httpStatus":401,"severity":"error","filePath":"apps/dokploy/server/api/routers/destination.ts","lineNumber":110,"sourceCode":"\t\t\t\t\tawait execAsync(rcloneCommand);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthrow new TRPCError({\n\t\t\t\t\tcode: \"BAD_REQUEST\",\n\t\t\t\t\tmessage:\n\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t? error?.message\n\t\t\t\t\t\t\t: \"Error connecting to bucket\",\n\t\t\t\t\tcause: error,\n\t\t\t\t});\n\t\t\t}\n\t\t}),\n\tone: withPermission(\"destination\", \"read\")\n\t\t.input(apiFindOneDestination)\n\t\t.query(async ({ input, ctx }) => {\n\t\t\tconst destination = await findDestinationById(input.destinationId);\n\t\t\tif (destination.organizationId !== ctx.session.activeOrganizationId) {\n\t\t\t\tthrow new TRPCError({\n\t\t\t\t\tcode: \"UNAUTHORIZED\",\n\t\t\t\t\tmessage: \"You are not allowed to access this destination\",\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn destination;\n\t\t}),\n\tall: withPermission(\"destination\", \"read\").query(async ({ ctx }) => {\n\t\treturn await db.query.destinations.findMany({\n\t\t\twhere: eq(destinations.organizationId, ctx.session.activeOrganizationId),\n\t\t\torderBy: [desc(destinations.createdAt)],\n\t\t});\n\t}),\n\tremove: withPermission(\"destination\", \"delete\")\n\t\t.input(apiRemoveDestination)\n\t\t.mutation(async ({ input, ctx }) => {\n\t\t\ttry {\n\t\t\t\tconst destination = await findDestinationById(input.destinationId);\n","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/Dokploy/dokploy/blob/546686ea3587f12ec5652217dedd9f7960fb6d15/apps/dokploy/server/api/routers/destination.ts#L92-L128","documentation":"Thrown by the `destination.one` tRPC procedure when the destination being fetched belongs to a different organization than the caller's active session organization. Dokploy scopes resources (destinations are S3-compatible backup targets) per organization, and this is a server-side tenant-isolation check that runs even after `withPermission('destination','read')` has authorized the permission level.","triggerScenarios":"Calling `destination.one` with a `destinationId` whose row in the `destination` table has an `organizationId` that differs from `ctx.session.activeOrganizationId` — e.g. copying a destinationId from another org, using a stale ID after the resource was reassigned, or having the wrong organization selected in the UI header.","commonSituations":"Multi-organization setups where the user switches organizations in the UI but an old tab/page still holds destinationIds from the previous org; importing or scripting requests with IDs from a different instance; a destination that was created under a different org by an admin.","solutions":["Verify the destinationId belongs to the currently active organization (check the organization switcher / session) before calling the API","Re-fetch the destination list via `destination.list` for the active org to get valid IDs","If the resource legitimately belongs to another org you are a member of, switch the active organization in the session/header and retry","If cross-org access is genuinely required, an admin must recreate or move the destination under the correct organization — there is no bypass flag"],"exampleFix":"// before\nconst dest = await trpc.destination.one.query({ destinationId: copiedId });\n// after — only query IDs from the active org's own list\nconst destinations = await trpc.destination.list.query();\nconst dest = await trpc.destination.one.query({\n  destinationId: destinations.find((d) => d.destinationId === copiedId)?.destinationId ?? destinations[0].destinationId,\n});","handlingStrategy":"validation","validationCode":"const destinations = await trpc.destination.list.query();\nconst ok = destinations.some(\n  (d) => d.destinationId === destinationId,\n);\nif (!ok) throw new Error('destination not accessible in active organization');\nconst dest = await trpc.destination.one.query({ destinationId });","typeGuard":null,"tryCatchPattern":"try {\n  const dest = await trpc.destination.one.query({ destinationId });\n} catch (e) {\n  if (e instanceof TRPCClientError && e.data?.code === 'UNAUTHORIZED') {\n    // refresh org context / destination list, do not retry blindly\n  }\n  throw e;\n}","preventionTips":["Always source resource IDs from a list call made under the current session","Reset stored IDs whenever the active organization changes","Never hard-code destinationIds in scripts"],"tags":["dokploy","trpc","multi-tenant","authorization","destination","s3-backup"],"backgroundTag":"cross-tenant-resource-access-denied","analyzedSha":"546686ea3587f12ec5652217dedd9f7960fb6d15","analyzedAt":"2026-08-27T05:18:58.095Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}