{"record":{"id":"c5e433a16ced9b60","repo":"different-ai/openwork","slug":"failed-to-grant-plugin-access-response-status","errorCode":null,"errorMessage":"Failed to grant plugin access (${response.status}).","messagePattern":"Failed to grant plugin access \\((.+?)\\)\\.","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/plugin-access-data.tsx","lineNumber":118,"sourceCode":"type GrantPluginAccessBody =\n  | { orgMembershipId: string; teamId?: never; orgWide?: never; role: PluginAccessRole }\n  | { orgMembershipId?: never; teamId: string; orgWide?: never; role: PluginAccessRole }\n  | { orgMembershipId?: never; teamId?: never; orgWide: true; role: PluginAccessRole };\n\nexport function useGrantPluginAccess() {\n  const queryClient = useQueryClient();\n  const { runReauthableAction } = useOrgDashboard();\n\n  return useMutation({\n    mutationFn: async (input: { pluginId: string; body: GrantPluginAccessBody }) => {\n      await runReauthableAction(\"grant-plugin-access\", async () => {\n        const { response, payload } = await requestJson(\n          `/v1/plugins/${encodeURIComponent(input.pluginId)}/access`,\n          { method: \"POST\", body: JSON.stringify(input.body) },\n          15000,\n        );\n        if (!response.ok) {\n          throw getRequestError(payload, response, `Failed to grant plugin access (${response.status}).`);\n        }\n      });\n      return input.pluginId;\n    },\n    onSuccess: (pluginId) => {\n      queryClient.invalidateQueries({ queryKey: pluginAccessQueryKeys.detail(pluginId) });\n    },\n  });\n}\n\nexport function useRevokePluginAccess() {\n  const queryClient = useQueryClient();\n  const { runReauthableAction } = useOrgDashboard();\n\n  return useMutation({\n    mutationFn: async (input: { pluginId: string; grantId: string }) => {\n      await runReauthableAction(\"revoke-plugin-access\", async () => {\n        const { response, payload } = await requestJson(","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/plugin-access-data.tsx#L100-L136","documentation":"Thrown by useGrantPluginAccess when POST /v1/plugins/:id/access returns non-ok. getRequestError prefers the server's error message; otherwise the fallback with the HTTP status is used. A 403 'reauth' payload becomes ReauthRequiredError.","triggerScenarios":"Granting plugin access with an invalid body (unknown subject ID or role — 400), plugin not found (404), insufficient permission to share the plugin (403), expired token (401), or org plugin-access limits/payment_required.","commonSituations":"Sharing a plugin with a member removed from the org, an unpublished or deleted plugin still cached in the UI, or role enum drift between client and API versions.","solutions":["Check the status: 400 → validate the access body (subject and role) before sending; 404 → refresh pluginQueryKeys.all, the plugin was removed.","On 401/403, re-authenticate or confirm sharing permissions; handle ReauthRequiredError explicitly.","Invalidate pluginAccessQueryKeys.detail(pluginId) and refetch before retrying to avoid duplicates.","Resolve any payment_required gate reported in the server message."],"exampleFix":"// before\nthrow getRequestError(payload, response, `Failed to grant plugin access (${response.status}).`);\n// after\nif (isReauthRequiredError(await Promise.resolve())) return; // pattern: catch and branch\nconst err = getRequestError(payload, response, `Failed to grant plugin access (${response.status}).`);\nif (isReauthRequiredError(err)) return startReauth();\nthrow err;","handlingStrategy":"validation","validationCode":"if (!input.pluginId || typeof input.pluginId !== \"string\") throw new Error(\"pluginId is required.\");\nif (!isValidAccessBody(input.body)) throw new Error(\"Select a valid subject and role before granting plugin access.\");","typeGuard":"function isValidAccessBody(body: unknown): body is { subjectId: string; role: string } {\n  return typeof body === \"object\" && body !== null\n    && typeof (body as { subjectId?: unknown }).subjectId === \"string\"\n    && typeof (body as { role?: unknown }).role === \"string\";\n}","tryCatchPattern":"try {\n  await grantPluginAccess.mutateAsync({ pluginId, body });\n} catch (error) {\n  if (isReauthRequiredError(error)) return startReauth();\n  toast.error(error.message);\n  await queryClient.invalidateQueries({ queryKey: pluginAccessQueryKeys.detail(pluginId) });\n}","preventionTips":["Confirm the plugin still exists (fresh pluginQueryKeys.detail) before opening the share panel.","Validate the access body shape client-side before POSTing.","Handle ReauthRequiredError in every plugin-access mutation.","Refetch the access detail before retrying to avoid duplicate grants."],"tags":["http","api","plugin","access-control","react-query"],"backgroundTag":"http-non-ok-response","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}