{"record":{"id":"16e7d7676fd62846","repo":"Dokploy/dokploy","slug":"unauthorized-16e7d7","errorCode":"UNAUTHORIZED","errorMessage":"You don't have access to this project","messagePattern":"You don't have access to this project","errorType":"exception","errorClass":"TRPCError","httpStatus":401,"severity":"error","filePath":"apps/dokploy/server/api/routers/tag.ts","lineNumber":217,"sourceCode":"\t\t\t\t\t\teq(projects.organizationId, ctx.session.activeOrganizationId),\n\t\t\t\t\t),\n\t\t\t\t});\n\n\t\t\t\tif (!project) {\n\t\t\t\t\tthrow new TRPCError({\n\t\t\t\t\t\tcode: \"NOT_FOUND\",\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"Project not found or you don't have permission to modify it\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Verify the member has access to the project\n\t\t\t\tif (\n\t\t\t\t\tmemberRecord.role !== \"owner\" &&\n\t\t\t\t\tmemberRecord.role !== \"admin\" &&\n\t\t\t\t\t!memberRecord.accessedProjects.includes(input.projectId)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TRPCError({\n\t\t\t\t\t\tcode: \"UNAUTHORIZED\",\n\t\t\t\t\t\tmessage: \"You don't have access to this project\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Verify the tag belongs to the user's organization\n\t\t\t\tconst tag = await db.query.tags.findFirst({\n\t\t\t\t\twhere: and(\n\t\t\t\t\t\teq(tags.tagId, input.tagId),\n\t\t\t\t\t\teq(tags.organizationId, ctx.session.activeOrganizationId),\n\t\t\t\t\t),\n\t\t\t\t});\n\n\t\t\t\tif (!tag) {\n\t\t\t\t\tthrow new TRPCError({\n\t\t\t\t\t\tcode: \"NOT_FOUND\",\n\t\t\t\t\t\tmessage: \"Tag not found or you don't have permission to use it\",\n\t\t\t\t\t});","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/Dokploy/dokploy/blob/546686ea3587f12ec5652217dedd9f7960fb6d15/apps/dokploy/server/api/routers/tag.ts#L199-L235","documentation":"Role check in tag.assignToProject: non-owner/non-admin members may only assign tags to projects listed in their memberRecord.accessedProjects array. If the project is not in that array, UNAUTHORIZED is thrown even though the project and tag exist in the org.","triggerScenarios":"A member with role 'user' (or similar) calling tag.assignToProject for a project that was never granted to them via accessedProjects; owners/admins bypass this check.","commonSituations":"New team member tagging a project the org owner hasn't shared with them; project access revoked but the UI still shows tag controls; per-project permission model misunderstood as org-wide.","solutions":["Ask an owner/admin to grant the member access to the project (add it to accessedProjects)","Perform the tag assignment as an owner/admin","If access was recently granted, refresh the member record/session and retry"],"exampleFix":"// before\nawait api.tag.assignToProject({ projectId, tagId }); // as member\n// after\n// member checks their accessible projects first:\nconst me = await api.org.getMember(); // includes accessedProjects\nif (me.accessedProjects.includes(projectId) || ['owner','admin'].includes(me.role)) {\n  await api.tag.assignToProject({ projectId, tagId });\n}","handlingStrategy":"type-guard","validationCode":"const me = await api.org.getMember(); // role + accessedProjects\nconst canAssign = me.role === 'owner' || me.role === 'admin'\n  || me.accessedProjects.includes(projectId);\nif (canAssign) await api.tag.assignToProject({ projectId, tagId });","typeGuard":"const canAssignTagsToProject = (m: { role: string; accessedProjects: string[] }, projectId: string) =>\n  m.role === 'owner' || m.role === 'admin' || m.accessedProjects.includes(projectId);","tryCatchPattern":"try { await assignToProject({ projectId, tagId }); }\ncatch (e) { if (e.shape?.data?.code === 'UNAUTHORIZED') requestProjectAccess(projectId); else throw e; }","preventionTips":["Hide tag controls for projects the member can't access","Request per-project access before tagging","Remember: org membership alone does not grant project-level tag rights"],"tags":["authorization","rbac","project-access","tag","trpc"],"backgroundTag":"rbac-permission-denied","analyzedSha":"546686ea3587f12ec5652217dedd9f7960fb6d15","analyzedAt":"2026-08-27T05:18:58.095Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}