{"record":{"id":"3820b0ef6b5448a4","repo":"tinyhumansai/openhuman","slug":"mcp-health-operrorgeneric","errorCode":null,"errorMessage":"mcp.health.opErrorGeneric","messagePattern":"mcp\\.health\\.opErrorGeneric","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/src/components/channels/mcp/McpServersTab.tsx","lineNumber":448,"sourceCode":"    void fetchCatalog(\n      debouncedCatalogFilters.query,\n      debouncedCatalogFilters.transport,\n      catalogPage + 1,\n      true\n    );\n  };\n\n  // Bulk lifecycle actions for the health toolbar. One failure doesn't abort the\n  // batch (allSettled), and we always refresh status so the dots reflect reality\n  // — but if any call rejected we then throw so the toolbar can surface the\n  // failure (otherwise a partial/total failure would look like success).\n  const handleReconnectAll = useCallback(\n    async (serverIds: string[]) => {\n      log('reconnect all: %o', serverIds);\n      const results = await Promise.allSettled(serverIds.map(id => mcpClientsApi.connect(id)));\n      await fetchStatuses();\n      if (results.some(r => r.status === 'rejected')) {\n        throw new Error(t('mcp.health.opErrorGeneric'));\n      }\n    },\n    [fetchStatuses, t]\n  );\n\n  const handleDisconnectAll = useCallback(\n    async (serverIds: string[]) => {\n      log('disconnect all: %o', serverIds);\n      const results = await Promise.allSettled(serverIds.map(id => mcpClientsApi.disconnect(id)));\n      await fetchStatuses();\n      if (results.some(r => r.status === 'rejected')) {\n        throw new Error(t('mcp.health.opErrorGeneric'));\n      }\n    },\n    [fetchStatuses, t]\n  );\n\n  const selectedServer =","sourceCodeStart":430,"sourceCodeEnd":466,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/components/channels/mcp/McpServersTab.tsx#L430-L466","documentation":"Bulk reconnect from the MCP health toolbar: handleReconnectAll runs Promise.allSettled over mcpClientsApi.connect(id) for every selected server, always refreshes statuses so the health dots reflect reality, and only then throws the localized 'mcp.health.opErrorGeneric' if ANY individual connect rejected. Partial success is expected - the throw tells the toolbar 'not all succeeded' but carries no per-server detail.","triggerScenarios":"Selecting multiple servers and clicking Reconnect-all where at least one connect(id) rejects - unreachable server, spawn failure, invalid transport config, or auth error on any member of the batch.","commonSituations":"Bulk-selecting a mixed set of healthy and dead servers; a dead server's rejection masking that the rest reconnected; treating the generic toolbar error as 'everything failed' when the dots show otherwise.","solutions":["Read the per-server status dots after the refresh - they were updated before the throw and show which servers actually failed","Open the failing server's detail / reconnect it individually to get its real error message","Fix or remove the dead entries (bad config, unreachable host) so bulk actions can go green","If a transient network blip is suspected, run Reconnect-all again once"],"exampleFix":"// before - single generic error for any partial failure\nif (results.some(r => r.status === 'rejected')) {\n  throw new Error(t('mcp.health.opErrorGeneric'));\n}\n\n// after - keep the generic throw but include the failing ids for triage\nconst failed = results\n  .map((r, i) => (r.status === 'rejected' ? serverIds[i] : null))\n  .filter((id): id is string => id !== null);\nif (failed.length > 0) {\n  throw new Error(`${t('mcp.health.opErrorGeneric')} (${failed.join(', ')})`);\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// consume the bulk action knowing partial success is normal\ntry {\n  await handleReconnectAll(serverIds);\n} catch {\n  // dots were refreshed before the throw - trust them, not this message\n  await fetchStatuses();\n  // reconnect failures individually to obtain their concrete errors\n}","preventionTips":["After any bulk action, read the per-server status dots (refreshed before the throw) rather than the generic message","Prune dead/unreachable servers from the selection before bulk reconnecting","Treat 'some rejected' as a triage signal: drill into individual servers for real error text"],"tags":["mcp","bulk-action","reconnect","promise-allsettled","partial-failure","i18n"],"backgroundTag":"bulk-operation-partial-failure","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}