{"record":{"id":"98db2fa4a0d51595","repo":"different-ai/openwork","slug":"update-connection-access-response-was-incomplete","errorCode":null,"errorMessage":"Update connection access response was incomplete.","messagePattern":"Update connection access response was incomplete\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/mcp-connections-data.tsx","lineNumber":867,"sourceCode":"export function useReplaceMcpConnectionAccess() {\n  const queryClient = useQueryClient();\n  const { orgId, runReauthableAction } = useOrgDashboard();\n\n  return useMutation({\n    mutationFn: async (input: { connectionId: string; access: McpConnectionAccessInput }): Promise<string> => {\n      let result: string | null = null;\n      await runReauthableAction(\"replace-mcp-connection-access\", async () => {\n        const { response, payload } = await requestJson(\n          `/v1/mcp-connections/${encodeURIComponent(input.connectionId)}/access`,\n          { method: \"PUT\", headers: getOrgScopeHeaders(requireOrgId(orgId)), body: JSON.stringify({ access: input.access }) },\n          15000,\n        );\n        if (!response.ok) {\n          throw getRequestError(payload, response, `Failed to update connection access (${response.status}).`);\n        }\n        result = input.connectionId;\n      });\n      if (!result) throw new Error(\"Update connection access response was incomplete.\");\n      return result;\n    },\n    onSuccess: () => {\n      queryClient.invalidateQueries({ queryKey: mcpConnectionQueryKeys.all });\n    },\n  });\n}\n\nexport function useStartMcpConnectionOAuth() {\n  const { orgId } = useOrgDashboard();\n\n  return useMutation({\n    mutationFn: async (connectionId: string): Promise<{ status: \"connected\" | \"needs_auth\"; authorizeUrl: string | null }> => {\n      const { response, payload } = await requestJson(\n        `/v1/mcp-connections/${encodeURIComponent(connectionId)}/connect/start`,\n        { headers: getOrgScopeHeaders(requireOrgId(orgId)) },\n        20000,\n      );","sourceCodeStart":849,"sourceCodeEnd":885,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/mcp-connections-data.tsx#L849-L885","documentation":"The update-connection-access mutation assigns `result = input.connectionId` inside the runReauthableAction callback after a successful fetch. The connectionId is a local value, so `result` can only be falsy if the callback never ran to completion (e.g. re-auth wrapper resolved without executing) or connectionId was empty/undefined in the input. The guard surfaces that as a thrown error rather than silently resolving the mutation.","triggerScenarios":"mutateAsync on update connection access with input.connectionId undefined/empty string, or runReauthableAction resolving without re-running the callback after an auth prompt was dismissed.","commonSituations":"UI passed a stale/missing connectionId after a list refetch removed the row; expired Den session triggered re-auth that was cancelled; wrapper contract change after refactor.","solutions":["Validate input.connectionId is a non-empty string before calling mutateAsync","Confirm runReauthableAction re-executes its callback after successful re-auth and throws (not silently resolves) on dismissal","Log the callback execution to see whether the fetch+assignment path ran","Check that the access-toggle endpoint's 2xx response isn't short-circuiting the assignment"],"exampleFix":"// before\nif (!result) throw new Error(\"Update connection access response was incomplete.\");\n// after\nif (!result) {\n  throw new Error(`Update connection access: no connectionId (input.connectionId=${JSON.stringify(input.connectionId)}).`);\n}","handlingStrategy":"validation","validationCode":"function assertConnectionAccessInput(input: { connectionId: string; access: 'private' | 'shared' }) {\n  if (!input.connectionId) throw new Error('connectionId is required before updating access');\n  if (!['private', 'shared'].includes(input.access)) throw new Error(`invalid access: ${input.access}`);\n}","typeGuard":"function hasConnectionId(v: unknown): v is { connectionId: string } {\n  return isRecord(v) && typeof v.connectionId === 'string' && v.connectionId.length > 0;\n}","tryCatchPattern":"try {\n  await updateAccess.mutateAsync({ connectionId, access });\n} catch (e) {\n  showToast({ variant: 'error', title: 'Could not change access', description: e instanceof Error ? e.message : String(e) });\n  queryClient.invalidateQueries({ queryKey: mcpConnectionQueryKeys.all });\n}","preventionTips":["Disable access toggles for rows without a stable connectionId","Refetch the connection list before mutating after long idle periods","Keep wrapper callback-execute-once semantics","Test the expired-session + cancelled re-auth path"],"tags":["react-query","mutation","null-guard","api-response"],"backgroundTag":"empty-api-response","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}