{"record":{"id":"397474a79454fd62","repo":"mastra-ai/mastra","slug":"mcp-client-was-disconnected-while-recovering-the-f","errorCode":null,"errorMessage":"MCP client was disconnected while recovering the failed transport","messagePattern":"MCP client was disconnected while recovering the failed transport","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/mcp/src/client/client.ts","lineNumber":1070,"sourceCode":"\n      await this.connect();\n      this.log('debug', 'Successfully reconnected to MCP server');\n    })();\n    this.reconnectPromise = reconnectPromise;\n\n    try {\n      await reconnectPromise;\n    } finally {\n      if (this.reconnectPromise === reconnectPromise) {\n        this.reconnectPromise = null;\n      }\n    }\n  }\n\n  private async reconnectAfterTransportFailure(failedTransport: Transport | undefined, lifecycleGeneration: number) {\n    while (true) {\n      if (this.lifecycleGeneration !== lifecycleGeneration) {\n        throw new Error('MCP client was disconnected while recovering the failed transport');\n      }\n\n      const reconnectPromise = this.reconnectPromise;\n      if (reconnectPromise) {\n        await reconnectPromise;\n        // Re-evaluate after the owner clears the settled promise. The transport\n        // that failed may itself be the replacement created by that reconnect.\n        continue;\n      }\n\n      if (failedTransport && this.transport && this.transport !== failedTransport) {\n        this.log('debug', 'Connection was already replaced after the failed operation; skipping reconnect');\n        return;\n      }\n\n      await this.forceReconnect();\n\n      if (this.lifecycleGeneration !== lifecycleGeneration) {","sourceCodeStart":1052,"sourceCodeEnd":1088,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/mcp/src/client/client.ts#L1052-L1088","documentation":"reconnectAfterTransportFailure is a private recovery loop that retries reconnecting after a transport failure, but only while the client is still connected for the same lifecycle generation. If disconnect() runs during recovery (lifecycleGeneration changed), the loop aborts by throwing this error — recovery is meaningless on a client that was intentionally disconnected.","triggerScenarios":"The transport fails and reconnectAfterTransportFailure begins, then the user calls disconnect() (or a new connect() starts a new generation) before recovery completes; the next loop iteration detects the generation mismatch and throws.","commonSituations":"Application shutting down or swapping server configs while a background reconnect is in flight; a request awaiting recovery is cancelled by disconnect; concurrent connect/disconnect calls racing.","solutions":["Catch this error around operations that may span a disconnect and treat it as cancellation, not a fault","Avoid calling disconnect() while reconnect recovery is pending, or accept in-flight operations failing","Use the latest client instance after reconfiguring instead of the old one"],"exampleFix":"// before\nconst tools = await client.tools(); // may reject with disconnect-during-recovery\n// after\ntry {\n  const tools = await client.tools();\n} catch (e) {\n  if (e instanceof Error && e.message.includes('disconnected while recovering')) return; // cancelled\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await client.listResources();\n} catch (e) {\n  if (e instanceof Error && e.message.includes('disconnected while recovering')) {\n    return; // operation cancelled by disconnect(); not a fault\n  }\n  throw e;\n}","preventionTips":["Avoid disconnect() while operations are awaiting transport recovery","Serialize connect/disconnect calls; treat generation mismatch as cancellation","Use the fresh client instance after reconfiguration instead of a stale one"],"tags":["mcp","lifecycle","disconnect","reconnect","race"],"backgroundTag":"disconnected-during-reconnect","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}