different-ai/openwork · error · Error

Failed to update MCP tool policy (${response.status}).

Error message

Failed to update MCP tool policy (${response.status}).

What it means

Thrown by useUpdateMcpConnectionToolPolicy when the PUT/PATCH updating an MCP connection's tool policy returns a non-ok status (30000ms timeout). getRequestError prefers the server's error message, falling back to 'Failed to update MCP tool policy (<status>)'. On success the tools query is invalidated; on this throw the cached policy stays unchanged.

Source

Thrown at ee/apps/den-web/app/(den)/dashboard/_components/mcp-connections-data.tsx:336

  });
}

export function useUpdateMcpConnectionToolPolicy(connectionId: string) {
  const queryClient = useQueryClient();
  const { orgId } = useOrgDashboard();
  return useMutation({
    mutationFn: async (input: Pick<ExternalMcpToolPolicyView, "allDisabled" | "disabledTools">): Promise<ExternalMcpToolPolicyView> => {
      const { response, payload } = await requestJson(
        `/v1/mcp-connections/${encodeURIComponent(connectionId)}/tool-policy`,
        {
          method: "PUT",
          headers: getOrgScopeHeaders(requireOrgId(orgId)),
          body: JSON.stringify(input),
        },
        30000,
      );
      if (!response.ok) {
        throw getRequestError(payload, response, `Failed to update MCP tool policy (${response.status}).`);
      }
      const policy = isRecord(payload) ? parseExternalMcpToolPolicy(payload.policy) : null;
      if (!policy) throw new Error("MCP tool policy response was incomplete.");
      return policy;
    },
    onSuccess: () => queryClient.invalidateQueries({ queryKey: mcpConnectionQueryKeys.tools(orgId, connectionId) }),
  });
}

// The den-api tool run is bounded by its 150s MCP tool lifecycle deadline;
// give the request a little headroom so the server's structured failure
// arrives instead of a client-side timeout.
const RUN_TOOL_REQUEST_TIMEOUT_MS = 160000;

export function useRunMcpConnectionTool(connectionId: string) {
  const { orgId } = useOrgDashboard();
  return useMutation({
    mutationFn: async (input: { toolName: string; arguments: Record<string, unknown> }): Promise<ExternalMcpToolRun> => {

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. For 400/422, re-fetch the tool catalog first and rebuild the policy from the current tool list.
  2. For 403, obtain org admin/connection-admin permission or adjust org policy.
  3. For 404, refresh the connections list and reopen the settings for the correct connection.
  4. For 401, re-authenticate; handle isReauthRequiredError explicitly.
  5. For 5xx, retry with backoff and check server logs.

Example fix

// before
await updatePolicy(input);
// after
try {
  await updatePolicy(input);
} catch (err) {
  if (isReauthRequiredError(err)) { startReauth(); }
  else if (/\((400|422)\)/.test(err.message)) { await refetchTools(); rebuildPolicyFromCatalog(); }
  else showError(err.message);
}
Defensive patterns

Strategy: validation

Validate before calling

// validate the policy against the current catalog before submitting
const known = new Set(tools.map(t => t.name));
const invalid = Object.keys(input).filter(name => !known.has(name));
if (invalid.length) throw new Error(`Unknown tools in policy: ${invalid.join(", ")}`);

Type guard

function isValidationError(err: unknown): boolean {
  return err instanceof Error && /\((400|422)\)/.test(err.message);
}

Try / catch

try {
  await updatePolicy(input);
} catch (err) {
  if (isReauthRequiredError(err)) startReauth();
  else if (isValidationError(err)) { await refetchTools(); }
  else showError(err.message);
}

Prevention

When it happens

Trigger: Non-ok response from the tool-policy endpoint with the submitted policy body: 400/422 when the policy payload fails server validation (unknown tool names, bad allow/deny shape), 403 when org policy forbids editing tool permissions, 404 when the connection no longer exists, 401 for expired sessions, 5xx server faults.

Common situations: Editing policy for a connection that was deleted in another tab (stale id); submitting a policy referencing tools the server no longer lists; session expiry; role without connection-admin rights.

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


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/887236f9874a2f87. Report an issue: GitHub.