Skip to content

bug: CoreToolScheduler.dispose() leaves queued schedule() callers pending forever with leaked abort listeners #29030

Description

@aniruddhaadak80

What happened?

CoreToolScheduler.dispose() removes its MCP-progress subscription and aborts an internal controller, but never drains requestQueue nor rejects promises parked in _enqueueRequest(). Any caller whose schedule() is queued behind an active batch at teardown time has its promise settle never, leaking the 'abort' listener attached to the caller's signal and the queue entry itself.

Affected code

packages/core/src/scheduler/scheduler.ts:140-143:

dispose(): void {
  coreEvents.off(CoreEvent.McpProgress, this.handleMcpProgress);
  this.disposeController.abort();
}

packages/core/src/core/../scheduler/scheduler.ts:229-243 — the only paths that settle a queued promise are the caller's own abort signal or batch processing, neither of which can happen after dispose:

const abortHandler = () => {
  const index = this.requestQueue.findIndex((item) => item.requests === requests);
  if (index > -1) { this.requestQueue.splice(index, 1); reject(new Error('Tool call cancelled while in queue.')); }
};
// ... resolve/reject wrappers remove the listener only when settled

The sole drain point is _startBatch's loop over requestQueue; once disposed it never runs again.

How can this be reproduced?

  1. Start a long-running tool batch so subsequent requests queue.
  2. While item B sits in requestQueue, call scheduler.dispose().
  3. The caller of schedule() for B awaits forever; inspect signal.listenerCount('abort') to see the leaked listener.

What did you expect to happen?

Dispose should reject every queued promise (e.g., new Error('Scheduler disposed')) so callers fail fast and their listeners are removed.

Impact

Subagent/session teardown leaves callers hung indefinitely and retains closures per queued call.

Suggested direction

In dispose(), splice all queue entries and invoke their stored reject (the entries already carry settle callbacks that remove listeners).


Found by source audit on current main (commit 5411f113c); platform-independent. No open issue/PR covering this was found (searched: scheduler dispose).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/agentIssues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Qualitystatus/need-triageIssues that need to be triaged by the triage automation.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions