Skip to content

fix: remove dead code after tools throw and fix transport leak on connect error#342

Open
matingathani wants to merge 2 commits intostripe:mainfrom
matingathani:fix/dead-code-and-resource-leak
Open

fix: remove dead code after tools throw and fix transport leak on connect error#342
matingathani wants to merge 2 commits intostripe:mainfrom
matingathani:fix/dead-code-and-resource-leak

Conversation

@matingathani
Copy link
Copy Markdown
Contributor

Changes

Two unrelated bugs fixed in a single PR.


Bug 1 — Dead code after unconditional throw in language model providers

Files: llm/ai-sdk/provider/stripe-language-model.ts, llm/ai-sdk/provider/stripe-language-model-v3.ts

Both getArgs() methods threw unconditionally when options.tools was non-empty, but the code immediately following the throw computed tools and toolChoice variables that could never be reached:

// throw fires here when tools are present
if (options.tools && options.tools.length > 0) {
  throw new Error('Tool calling is not supported...');
}

// ❌ These lines are unreachable — tools is always undefined after the throw
const tools = options.tools && options.tools.length > 0
  ? options.tools.map(...)
  : undefined;

let toolChoice = ...;
if (options.toolChoice) { ... }
...
if (tools !== undefined) body.tools = tools;        // never executes
if (toolChoice !== undefined) body.tool_choice = toolChoice; // never executes

Fix: Removed the 30–40 lines of unreachable tools/toolChoice computation from both files.


Bug 2 — Transport connection leak in TypeScript MCP client

File: tools/typescript/src/shared/mcp-client.ts

In doConnect(), if client.connect() succeeded but the subsequent client.listTools() call threw an error, the catch block nulled out this.client and this.transport without closing the active connection first, leaking the underlying transport:

} catch (error) {
  // ❌ Active connection was abandoned here — client.close() never called
  this.client = null;
  this.transport = null;
  throw ...;
}

Fix: Call await this.client.close() before clearing references so the MCP connection is properly torn down on any connect-phase failure.


Testing

  • llm/ai-sdk: 327 tests pass
  • tools/typescript: 55 tests pass

…nect error

Two bugs fixed:

1. Dead code in stripe-language-model.ts and stripe-language-model-v3.ts

   Both files threw unconditionally when tools were provided, but then
   immediately computed unreachable `tools` and `toolChoice` variables.
   Those dead blocks have been removed.
   All 327 ai-sdk tests still pass.

2. Transport leak in mcp-client.ts (TypeScript toolkit)

   In doConnect(), if client.connect() succeeded but listTools() threw,
   the open MCP connection was abandoned without calling client.close(),
   leaking the underlying transport indefinitely.

   Fix: call client.close() before clearing references so the connection
   is properly torn down on any connect-phase error.
   All 55 TypeScript toolkit tests still pass.
Copilot AI review requested due to automatic review settings March 30, 2026 00:23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes two bugs across the AI SDK Stripe language model providers and the TypeScript MCP client: removing unreachable tool-handling code paths and ensuring MCP connections are properly closed on connect-phase failures.

Changes:

  • Removed unreachable tools (and related) request-body construction in Stripe language model providers when tool calling is unsupported.
  • Added connect-error cleanup in StripeMcpClient to close an established MCP connection before clearing references.
  • Minor formatting/cleanup in request-body optional parameter handling.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
tools/typescript/src/shared/mcp-client.ts Closes the MCP client during connect failure cleanup to prevent transport leaks.
llm/ai-sdk/provider/stripe-language-model.ts Removes dead tool/tool-choice request construction after the “tools unsupported” throw.
llm/ai-sdk/provider/stripe-language-model-v3.ts Same dead-code removal for the V3 provider variant.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +116 to 124
// Close the active connection before clearing references to avoid leaking
// the underlying transport if connect() succeeded but listTools() failed.
try {
if (this.client) await this.client.close();
} catch {
// Ignore close errors during cleanup
}
this.client = null;
this.transport = null;
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new cleanup closes this.client, but there’s no test coverage that close() is invoked when connect() succeeds and listTools() throws. Adding a Jest test that mocks listTools to reject and asserts client.close is awaited (and that connect() rejects with the wrapped error) would prevent regressions of the transport leak fix.

Copilot uses AI. Check for mistakes.
Comment on lines +264 to 271
// Tool calling is not supported by the Stripe AI SDK Provider.
if (options.tools && options.tools.length > 0) {
throw new Error(
'Tool calling is not supported by the Stripe AI SDK Provider. ' +
'The llm.stripe.com API does not currently support function calling or tool use. ' +
'Please remove the tools parameter from your request.'
'The llm.stripe.com API does not currently support function calling or tool use. ' +
'Please remove the tools parameter from your request.'
);
}
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After removing the toolChoice mapping, options.toolChoice is now silently ignored when options.tools is empty. Since tool calling is explicitly unsupported, it would be clearer/safer to also reject options.toolChoice (or at least warn) and update the error message to mention toolChoice as unsupported, to avoid a behavior change that’s hard for callers to notice.

Copilot uses AI. Check for mistakes.
@@ -239,38 +240,6 @@ export class StripeLanguageModelV3 implements LanguageModelV3 {
);
}

Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

options.toolChoice is no longer forwarded (and is silently ignored) when options.tools is empty. Given the explicit “tool calling not supported” stance, consider explicitly throwing when toolChoice is provided as well (and adjusting the message), so callers don’t think the setting is taking effect.

Suggested change
if (options.toolChoice !== undefined) {
throw new Error(
'Tool calling is not supported by the Stripe AI SDK Provider. ' +
'The llm.stripe.com API does not currently support function calling or tool use. ' +
'Please remove the toolChoice parameter (and any tools) from your request.'
);
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants