{"record":{"id":"1f596ee0c5d07793","repo":"different-ai/openwork","slug":"failed-to-revoke-dashboard-access-response-stat","errorCode":null,"errorMessage":"Failed to revoke dashboard access (${response.status}).","messagePattern":"Failed to revoke dashboard access \\((.+?)\\)\\.","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/org-dashboards-data.tsx","lineNumber":359,"sourceCode":"      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(\n          `/v1/dashboards/${encodeURIComponent(input.dashboardId)}/access/${encodeURIComponent(input.grantId)}`,\n          { method: \"DELETE\" },\n          15000,\n        );\n        if (response.status !== 204 && !response.ok) {\n          throw getRequestError(payload, response, `Failed to revoke 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\n/** A flat catalog containing only connections that expose launchable MCP Apps. */\nexport function useConnectionMcpAppCatalog(connections: Array<{ id: string; name: string }>) {\n  const { orgContext } = useOrgDashboard();\n  const organizationId = orgContext?.organization.id ?? \"\";\n  return useQueries({\n    queries: connections.map((connection) => ({\n      enabled: Boolean(organizationId),\n      queryKey: orgDashboardsQueryKeys.connectionApps(organizationId, connection.id),","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/org-dashboards-data.tsx#L341-L377","documentation":"Thrown by useRevokeDashboardAccess when DELETE /v1/dashboards/:id/access/:grantId returns neither 204 nor ok. Like the sibling delete mutation, non-204 success bodies are tolerated; anything else non-ok raises this error with the status in the message.","triggerScenarios":"Revoking a grant that was already removed (404 — e.g. two admins revoking simultaneously), missing permission to manage access (403), expired session (401), malformed grantId, or server error during revocation.","commonSituations":"The access list is stale and the grant was already revoked elsewhere; the UI kept an old grantId after a refetch raced with the mutation.","solutions":["On 404, invalidate orgDashboardsQueryKeys.access and refetch — the grant is already gone; treat as success.","On 401/403, re-authenticate or verify access-management permissions.","On 5xx, retry after refetching; confirm whether revocation succeeded before assuming failure.","Ensure grantId is a current, valid ID from the latest access list response."],"exampleFix":"// before\nif (response.status !== 204 && !response.ok) {\n  throw getRequestError(payload, response, `Failed to revoke dashboard access (${response.status}).`);\n}\n// after\nif (response.status === 404) return input.dashboardId; // grant already revoked\nif (response.status !== 204 && !response.ok) {\n  throw getRequestError(payload, response, `Failed to revoke dashboard access (${response.status}).`);\n}","handlingStrategy":"try-catch","validationCode":"if (!input.grantId || typeof input.grantId !== \"string\") {\n  throw new Error(\"A valid grantId is required to revoke access.\");\n}","typeGuard":"function isGrantId(value: unknown): value is string {\n  return typeof value === \"string\" && value.length > 0;\n}","tryCatchPattern":"try {\n  await revokeAccess.mutateAsync({ dashboardId, grantId });\n} catch (error) {\n  if (isReauthRequiredError(error)) return startReauth();\n  if (error.message.includes(\"(404)\")) return; // already revoked; refetch\n  toast.error(error.message);\n} finally {\n  await queryClient.invalidateQueries({ queryKey: orgDashboardsQueryKeys.access(organizationId, dashboardId) });\n}","preventionTips":["Treat 404 on revoke as success — the grant was already removed.","Always invalidate the access list after revoke attempts.","Avoid holding stale grantIds from a long-open access panel; refetch on focus.","Gate the revoke action on the user's access-management permission."],"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"}