{"record":{"id":"887236f9874a2f87","repo":"different-ai/openwork","slug":"failed-to-update-mcp-tool-policy-response-statu","errorCode":null,"errorMessage":"Failed to update MCP tool policy (${response.status}).","messagePattern":"Failed to update MCP tool policy \\((.+?)\\)\\.","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/mcp-connections-data.tsx","lineNumber":336,"sourceCode":"  });\n}\n\nexport function useUpdateMcpConnectionToolPolicy(connectionId: string) {\n  const queryClient = useQueryClient();\n  const { orgId } = useOrgDashboard();\n  return useMutation({\n    mutationFn: async (input: Pick<ExternalMcpToolPolicyView, \"allDisabled\" | \"disabledTools\">): Promise<ExternalMcpToolPolicyView> => {\n      const { response, payload } = await requestJson(\n        `/v1/mcp-connections/${encodeURIComponent(connectionId)}/tool-policy`,\n        {\n          method: \"PUT\",\n          headers: getOrgScopeHeaders(requireOrgId(orgId)),\n          body: JSON.stringify(input),\n        },\n        30000,\n      );\n      if (!response.ok) {\n        throw getRequestError(payload, response, `Failed to update MCP tool policy (${response.status}).`);\n      }\n      const policy = isRecord(payload) ? parseExternalMcpToolPolicy(payload.policy) : null;\n      if (!policy) throw new Error(\"MCP tool policy response was incomplete.\");\n      return policy;\n    },\n    onSuccess: () => queryClient.invalidateQueries({ queryKey: mcpConnectionQueryKeys.tools(orgId, connectionId) }),\n  });\n}\n\n// The den-api tool run is bounded by its 150s MCP tool lifecycle deadline;\n// give the request a little headroom so the server's structured failure\n// arrives instead of a client-side timeout.\nconst RUN_TOOL_REQUEST_TIMEOUT_MS = 160000;\n\nexport function useRunMcpConnectionTool(connectionId: string) {\n  const { orgId } = useOrgDashboard();\n  return useMutation({\n    mutationFn: async (input: { toolName: string; arguments: Record<string, unknown> }): Promise<ExternalMcpToolRun> => {","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/mcp-connections-data.tsx#L318-L354","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["For 400/422, re-fetch the tool catalog first and rebuild the policy from the current tool list.","For 403, obtain org admin/connection-admin permission or adjust org policy.","For 404, refresh the connections list and reopen the settings for the correct connection.","For 401, re-authenticate; handle isReauthRequiredError explicitly.","For 5xx, retry with backoff and check server logs."],"exampleFix":"// before\nawait updatePolicy(input);\n// after\ntry {\n  await updatePolicy(input);\n} catch (err) {\n  if (isReauthRequiredError(err)) { startReauth(); }\n  else if (/\\((400|422)\\)/.test(err.message)) { await refetchTools(); rebuildPolicyFromCatalog(); }\n  else showError(err.message);\n}","handlingStrategy":"validation","validationCode":"// validate the policy against the current catalog before submitting\nconst known = new Set(tools.map(t => t.name));\nconst invalid = Object.keys(input).filter(name => !known.has(name));\nif (invalid.length) throw new Error(`Unknown tools in policy: ${invalid.join(\", \")}`);","typeGuard":"function isValidationError(err: unknown): boolean {\n  return err instanceof Error && /\\((400|422)\\)/.test(err.message);\n}","tryCatchPattern":"try {\n  await updatePolicy(input);\n} catch (err) {\n  if (isReauthRequiredError(err)) startReauth();\n  else if (isValidationError(err)) { await refetchTools(); }\n  else showError(err.message);\n}","preventionTips":["Rebuild policies from a freshly fetched tool catalog, never from stale UI state","Confirm the connection still exists before editing its policy","Require connection-admin role before exposing policy editing","Invalidate the tools query after updates so subsequent edits use fresh data"],"tags":["http","den-api","mcp","policy"],"backgroundTag":"http-request-failed","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}