{"record":{"id":"961f3dd6f1c42adf","repo":"tinyhumansai/openhuman","slug":"mcp-detail-reconfigurereconnectfailed","errorCode":null,"errorMessage":"mcp.detail.reconfigureReconnectFailed","messagePattern":"mcp\\.detail\\.reconfigureReconnectFailed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/components/channels/mcp/InstalledServerDetail.tsx","lineNumber":213,"sourceCode":"      // have a value or the server loses required env on reconnect. Mirror the\n      // install dialog's validation.\n      for (const key of visibleEnvKeys) {\n        if (!reconfigValues[key]?.trim()) {\n          throw new Error(t('mcp.install.missingRequired').replace('{key}', key));\n        }\n      }\n      log('reconfigure save server_id=%s', server.server_id);\n      const result = await mcpClientsApi.updateEnv({\n        server_id: server.server_id,\n        env: reconfigValues,\n      });\n      setTools(result.tools ?? []);\n      if (result.status === 'unauthorized') {\n        // A 401 after reconfigure: show the actionable auth reason (use Sign in\n        // / token rejected / credential required) the same way the Connect\n        // dialog does — the raw 401 message is withheld server-side (#4289).\n        const key = authHintMessageKey(result.auth_hint);\n        throw new Error(key ? t(key) : t('mcp.detail.reconfigureReconnectFailed'));\n      }\n      if (result.status !== 'connected') {\n        throw new Error(result.error ?? t('mcp.detail.reconfigureReconnectFailed'));\n      }\n      setReconfigDone(true);\n      setReconfigOpen(false);\n    });\n  }, [server.env_keys, server.server_id, reconfigValues, runBusy, t]);\n\n  return (\n    <div className=\"space-y-4\">\n      {/* Header */}\n      <div className=\"flex items-start gap-3\">\n        {server.icon_url ? (\n          <img\n            src={server.icon_url}\n            alt=\"\"\n            className=\"w-10 h-10 rounded shrink-0 object-contain bg-surface border border-line-subtle\"","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/app/src/components/channels/mcp/InstalledServerDetail.tsx#L195-L231","documentation":"After updateEnv the client reconnects; a resulting 'unauthorized' status normally maps to an actionable auth hint via authHintMessageKey (use Sign in / token rejected / credential required), but when auth_hint is absent or unrecognized the generic reconfigureReconnectFailed message is shown — the raw 401 body is deliberately withheld server-side (#4289).","triggerScenarios":"Env update succeeded but reconnect got a 401 with auth_hint null or an uncategorized value: token expired between operations, credential rejected without a classified reason.","commonSituations":"API key rotated or expired mid-session; server changed its auth scheme so the hint classifier misses it.","solutions":["Open the Connect dialog for that server and re-authenticate from scratch","Re-enter the credential in reconfigure, making sure it is a fresh, valid token/key","If it persists, disconnect and reinstall the server, then connect again"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before saving, pre-validate that credentials look present and fresh:\nconst required = visibleEnvKeys.filter(k => /token|key|secret/i.test(k));\nconst stale = required.filter(k => !reconfigValues[k]?.trim());\nif (stale.length) { /* block save and prompt re-entry */ }","typeGuard":"const hasAuthHint = (h: unknown): h is string => typeof h === 'string' && h.length > 0;","tryCatchPattern":"try {\n  const result = await mcpClientsApi.updateEnv({ server_id, env });\n  if (result.status === 'unauthorized' && !result.auth_hint) {\n    // fall back to the Connect dialog flow instead of looping on reconfigure\n    openConnectDialog();\n    return;\n  }\n} catch (e) { /* surface, then guide user to re-auth */ }","preventionTips":["Treat uncategorized 401 after reconfigure as 're-authenticate', not 'retry same values'","Rotate long-lived tokens on a schedule so they don't expire between operations","Keep the Connect dialog available as the recovery path for auth failures"],"tags":["mcp","auth","unauthorized","reconfigure"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}