different-ai/openwork · error
Failed to revoke plugin access (${response.status}).
Error message
Failed to revoke plugin access (${response.status}). What it means
Thrown by useRevokePluginAccess when DELETE /v1/plugins/:id/access/:grantId returns neither 204 nor ok. The message embeds the HTTP status unless the payload supplies a server error message. 403 'reauth' payloads surface as ReauthRequiredError instead.
Source
Thrown at ee/apps/den-web/app/(den)/dashboard/_components/plugin-access-data.tsx:142
queryClient.invalidateQueries({ queryKey: pluginAccessQueryKeys.detail(pluginId) });
},
});
}
export function useRevokePluginAccess() {
const queryClient = useQueryClient();
const { runReauthableAction } = useOrgDashboard();
return useMutation({
mutationFn: async (input: { pluginId: string; grantId: string }) => {
await runReauthableAction("revoke-plugin-access", async () => {
const { response, payload } = await requestJson(
`/v1/plugins/${encodeURIComponent(input.pluginId)}/access/${encodeURIComponent(input.grantId)}`,
{ method: "DELETE" },
15000,
);
if (response.status !== 204 && !response.ok) {
throw getRequestError(payload, response, `Failed to revoke plugin access (${response.status}).`);
}
});
return input.pluginId;
},
onSuccess: (pluginId) => {
queryClient.invalidateQueries({ queryKey: pluginAccessQueryKeys.detail(pluginId) });
},
});
}
View on GitHub (pinned to 2b7df46e8a)
Solutions
- On 404, refetch pluginAccessQueryKeys.detail(pluginId) and treat the grant as already revoked.
- On 401/403, re-authenticate or verify access-management rights.
- On 5xx, retry after confirming current grant state to avoid acting on stale data.
- Validate grantId came from the latest access list response before calling revoke.
Example fix
// before
if (response.status !== 204 && !response.ok) {
throw getRequestError(payload, response, `Failed to revoke plugin access (${response.status}).`);
}
// after
if (response.status === 404) return input.pluginId; // already revoked
if (response.status !== 204 && !response.ok) {
throw getRequestError(payload, response, `Failed to revoke plugin access (${response.status}).`);
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!input.pluginId || !input.grantId || typeof input.grantId !== "string") {
throw new Error("A valid pluginId and grantId are required to revoke access.");
} Type guard
function isGrantId(value: unknown): value is string {
return typeof value === "string" && value.length > 0;
} Try / catch
try {
await revokePluginAccess.mutateAsync({ pluginId, grantId });
} catch (error) {
if (isReauthRequiredError(error)) return startReauth();
if (error.message.includes("(404)")) return; // already revoked
toast.error(error.message);
} finally {
await queryClient.invalidateQueries({ queryKey: pluginAccessQueryKeys.detail(pluginId) });
} Prevention
- Treat 404 on revoke as already-revoked success and refetch.
- Invalidate pluginAccessQueryKeys.detail(pluginId) after every revoke attempt.
- Use grantIds from the latest access list response only.
- Hide revoke actions for users without access-management permission.
When it happens
Trigger: Revoking an access grant that no longer exists (404 — concurrent revocation or stale list), lacking permission to manage plugin access (403), expired session (401), malformed grantId, or server error.
Common situations: Stale access list where the grant was already removed; admin permissions changed mid-session; plugin itself deleted while its access list was still open.
Related errors
- Failed to grant plugin access (${response.status}).
- Failed to grant dashboard access (${response.status}).
- Failed to revoke dashboard access (${response.status}).
- Failed to update plugin (${response.status}).
- Failed to load dashboards (${response.status}).
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/37af42adadce2869.
Report an issue: GitHub.