different-ai/openwork · error
Failed to grant dashboard access (${response.status}).
Error message
Failed to grant dashboard access (${response.status}). What it means
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.
Source
Thrown at ee/apps/den-web/app/(den)/dashboard/_components/org-dashboards-data.tsx:335
type GrantDashboardAccessBody =
| { orgMembershipId: string; teamId?: never; orgWide?: never; role: DashboardAccessRole }
| { orgMembershipId?: never; teamId: string; orgWide?: never; role: DashboardAccessRole }
| { orgMembershipId?: never; teamId?: never; orgWide: true; role: DashboardAccessRole };
export function useGrantDashboardAccess() {
const queryClient = useQueryClient();
const { orgContext, runReauthableAction } = useOrgDashboard();
const organizationId = orgContext?.organization.id ?? "";
return useMutation({
mutationFn: async (input: { dashboardId: string; body: GrantDashboardAccessBody }) => {
await runReauthableAction("grant-dashboard-access", async () => {
const { response, payload } = await requestJson(
`/v1/dashboards/${encodeURIComponent(input.dashboardId)}/access`,
{ method: "POST", body: JSON.stringify(input.body) },
15000,
);
if (!response.ok) {
throw getRequestError(payload, response, `Failed to grant dashboard access (${response.status}).`);
}
});
return input.dashboardId;
},
onSuccess: (dashboardId) => {
queryClient.invalidateQueries({ queryKey: orgDashboardsQueryKeys.access(organizationId, dashboardId) });
},
});
}
export function useRevokeDashboardAccess() {
const queryClient = useQueryClient();
const { orgContext, runReauthableAction } = useOrgDashboard();
const organizationId = orgContext?.organization.id ?? "";
return useMutation({
mutationFn: async (input: { dashboardId: string; grantId: string }) => {
await runReauthableAction("revoke-dashboard-access", async () => {
const { response, payload } = await requestJson(View on GitHub (pinned to 2b7df46e8a)
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.
Example fix
// before
await requestJson(`/v1/dashboards/${encodeURIComponent(input.dashboardId)}/access`, { method: "POST", body: JSON.stringify(input.body) }, 15000);
// after
if (!input.body || typeof input.body.role !== "string" || !input.body.subjectId) {
throw new Error("Select a valid member and role before granting access.");
}
await requestJson(`/v1/dashboards/${encodeURIComponent(input.dashboardId)}/access`, { method: "POST", body: JSON.stringify(input.body) }, 15000); Defensive patterns
Strategy: validation
Validate before calling
if (!input.body?.subjectId || typeof input.body.role !== "string" || input.body.role.length === 0) {
throw new Error("Select a valid member/group and role before granting dashboard access.");
} Type guard
function isValidAccessBody(body: unknown): body is { subjectId: string; role: string } {
return typeof body === "object" && body !== null
&& typeof (body as { subjectId?: unknown }).subjectId === "string"
&& typeof (body as { role?: unknown }).role === "string";
} Try / catch
try {
await grantAccess.mutateAsync({ dashboardId, body });
} catch (error) {
if (isReauthRequiredError(error)) return startReauth();
toast.error(error.message);
await queryClient.invalidateQueries({ queryKey: orgDashboardsQueryKeys.access(organizationId, dashboardId) });
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Failed to revoke dashboard access (${response.status}).
- Failed to create the dashboard (${response.status}).
- Failed to update the dashboard (${response.status}).
- Failed to delete the dashboard (${response.status}).
- Failed to grant plugin access (${response.status}).
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/5268fe56d38546fe.
Report an issue: GitHub.