{"record":{"id":"5268fe56d38546fe","repo":"different-ai/openwork","slug":"failed-to-grant-dashboard-access-response-statu","errorCode":null,"errorMessage":"Failed to grant dashboard access (${response.status}).","messagePattern":"Failed to grant dashboard access \\((.+?)\\)\\.","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/org-dashboards-data.tsx","lineNumber":335,"sourceCode":"type GrantDashboardAccessBody =\n  | { orgMembershipId: string; teamId?: never; orgWide?: never; role: DashboardAccessRole }\n  | { orgMembershipId?: never; teamId: string; orgWide?: never; role: DashboardAccessRole }\n  | { orgMembershipId?: never; teamId?: never; orgWide: true; role: DashboardAccessRole };\n\nexport function useGrantDashboardAccess() {\n  const queryClient = useQueryClient();\n  const { orgContext, runReauthableAction } = useOrgDashboard();\n  const organizationId = orgContext?.organization.id ?? \"\";\n  return useMutation({\n    mutationFn: async (input: { dashboardId: string; body: GrantDashboardAccessBody }) => {\n      await runReauthableAction(\"grant-dashboard-access\", async () => {\n        const { response, payload } = await requestJson(\n          `/v1/dashboards/${encodeURIComponent(input.dashboardId)}/access`,\n          { method: \"POST\", body: JSON.stringify(input.body) },\n          15000,\n        );\n        if (!response.ok) {\n          throw getRequestError(payload, response, `Failed to grant dashboard access (${response.status}).`);\n        }\n      });\n      return input.dashboardId;\n    },\n    onSuccess: (dashboardId) => {\n      queryClient.invalidateQueries({ queryKey: orgDashboardsQueryKeys.access(organizationId, dashboardId) });\n    },\n  });\n}\n\nexport function useRevokeDashboardAccess() {\n  const queryClient = useQueryClient();\n  const { orgContext, runReauthableAction } = useOrgDashboard();\n  const organizationId = orgContext?.organization.id ?? \"\";\n  return useMutation({\n    mutationFn: async (input: { dashboardId: string; grantId: string }) => {\n      await runReauthableAction(\"revoke-dashboard-access\", async () => {\n        const { response, payload } = await requestJson(","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/org-dashboards-data.tsx#L317-L353","documentation":"Thrown by useGrantDashboardAccess when POST /v1/dashboards/:id/access returns non-ok. The fallback message carries the HTTP status; a server-provided error message overrides it. A 403 'reauth' payload is raised as ReauthRequiredError instead.","triggerScenarios":"Granting access with a body the server rejects (unknown member/group ID, invalid role enum — 400), target grantee not in the org (404), caller lacks share permissions (403), expired token (401), or payment/seat gating on the workspace.","commonSituations":"Sharing a dashboard with a user who was removed from the org, selecting a role value not supported by the current API version, or stale member list in the UI.","solutions":["Read the status: 400 → validate the access body (member/group IDs and role) against the current API schema; 404 → refresh the member list, the grantee no longer exists.","On 401/403, re-authenticate or confirm the caller has dashboard-sharing rights.","Invalidate orgDashboardsQueryKeys.access and refetch before retrying to avoid duplicate grants.","Check the thrown message for payment_required and resolve the org billing gate."],"exampleFix":"// before\nawait requestJson(`/v1/dashboards/${encodeURIComponent(input.dashboardId)}/access`, { method: \"POST\", body: JSON.stringify(input.body) }, 15000);\n// after\nif (!input.body || typeof input.body.role !== \"string\" || !input.body.subjectId) {\n  throw new Error(\"Select a valid member and role before granting access.\");\n}\nawait requestJson(`/v1/dashboards/${encodeURIComponent(input.dashboardId)}/access`, { method: \"POST\", body: JSON.stringify(input.body) }, 15000);","handlingStrategy":"validation","validationCode":"if (!input.body?.subjectId || typeof input.body.role !== \"string\" || input.body.role.length === 0) {\n  throw new Error(\"Select a valid member/group and role before granting dashboard access.\");\n}","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 grantAccess.mutateAsync({ dashboardId, body });\n} catch (error) {\n  if (isReauthRequiredError(error)) return startReauth();\n  toast.error(error.message);\n  await queryClient.invalidateQueries({ queryKey: orgDashboardsQueryKeys.access(organizationId, dashboardId) });\n}","preventionTips":["Build the grant UI from a freshly fetched member list, not cached data.","Restrict role choices to values the API version supports.","Refetch the access list before retrying a failed grant to avoid duplicates.","Watch for payment_required in server messages and route to billing."],"tags":["http","api","dashboard","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"}