different-ai/openwork · error
Failed to revoke access (${response.status}).
Error message
Failed to revoke access (${response.status}). What it means
Thrown by useRevokeTeamPluginAccess when DELETE /v1/plugins/{pluginId}/access/{grantId} returns a status other than 204 or generic non-ok. This removes a team's granted access to a plugin; on success the team-access detail query is invalidated. Like the other den-web mutations, getRequestError appends the server message and converts 403 error:'reauth' into ReauthRequiredError.
Source
Thrown at ee/apps/den-web/app/(den)/dashboard/_components/team-access-data.tsx:146
.filter((item): item is TeamPluginAccessItem => item !== null);
},
});
}
export function useRevokeTeamPluginAccess() {
const queryClient = useQueryClient();
const { runReauthableAction } = useOrgDashboard();
return useMutation({
mutationFn: async (input: { teamId: string; pluginId: string; grantId: string }) => {
await runReauthableAction("revoke-team-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 access (${response.status}).`);
}
});
return input.teamId;
},
onSuccess: (teamId) => {
queryClient.invalidateQueries({ queryKey: teamAccessQueryKeys.detail(teamId) });
},
});
}
View on GitHub (pinned to 2b7df46e8a)
Solutions
- Read the appended server message to distinguish 403 (permissions) vs 404 (already revoked).
- On 404, treat the grant as already revoked: invalidate teamAccessQueryKeys.detail(teamId) and refresh the UI.
- Handle ReauthRequiredError (sign-in) and retry the revoke.
- Verify the caller still has plugin/org admin rights for 403.
- Retry on 429/5xx with backoff; check Den server health for persistent failures.
Example fix
// before
revokeAccess.mutate(input, { onError: (e) => toast(e.message) });
// after: tolerate already-revoked
revokeAccess.mutate(input, {
onError: (e) => {
if (/\b404\b/.test(e.message)) {
queryClient.invalidateQueries({ queryKey: teamAccessQueryKeys.detail(input.teamId) });
return;
}
toast(e.message);
},
}); Defensive patterns
Strategy: try-catch
Validate before calling
if (!input.pluginId || !input.grantId) throw new Error("pluginId and grantId are required to revoke access."); Type guard
function isReauthRequiredError(e: unknown): e is ReauthRequiredError {
return e instanceof ReauthRequiredError;
} Try / catch
try {
await revokeAccess.mutateAsync(input);
} catch (err) {
if (isReauthRequiredError(err)) { promptSignIn(); return; }
if (/\b404\b/.test(err.message)) { // grant already revoked elsewhere
queryClient.invalidateQueries({ queryKey: teamAccessQueryKeys.detail(input.teamId) });
return;
}
showError(err.message);
} Prevention
- Invalidate teamAccessQueryKeys.detail(teamId) on success (hook already does) so stale grant ids leave the UI.
- Treat 404 as idempotent success for revoke.
- Gate revoke buttons on plugin/org admin permission.
- Refresh the grant list if the plugin detail query indicates the plugin changed.
- Use backoff for 429/5xx instead of immediate user retries.
When it happens
Trigger: DELETE /v1/plugins/{pluginId}/access/{grantId} returns 401 (expired session), 403 (no admin rights over the plugin/org, or reauth challenge), 404 (pluginId or grantId no longer exists — grant already revoked elsewhere), 409 (grant is locked, e.g. required by an assignment policy), 429, or 5xx. 15s timeout.
Common situations: Two admins revoke the same grant concurrently (second gets 404); the plugin was deleted leaving stale grant ids in the UI; role downgraded mid-session; long-idle tab with expired token.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Failed to load organizations (${response.status}).
- Failed to switch organization (${response.status}).
- Failed to load organization (${response.status}).
- Failed to create organization (${response.status}).
- Failed to grant dashboard access (${response.status}).
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/a8080b48b8862de6.
Report an issue: GitHub.