google-gemini/gemini-cli · error

LegacyAgentSession.send() cannot be called while a stream…

Error message

LegacyAgentSession.send() cannot be called while a stream is active.

What it means

Thrown by `LegacyAgentSession.send` when a second send arrives while `_activeStreamId` is still set — i.e. a stream is mid-flight. The legacy adapter has no correlation semantics for interleaved in-stream sends (updates, elicitation responses), so it rejects all concurrent sends defensively until the active stream completes and clears the flag.

Solutions

  1. Await the full resolution of the active stream (consume until `agent_end`) before issuing the next `send`.
  2. Serialize sends through a queue so only one stream is active at a time.
  3. Disable/ignore the submit affordance in the UI while a stream is active.
  4. If you genuinely need concurrent or in-stream sends, switch to a non-legacy session implementation that defines those semantics.

Example fix

// before
legacySession.send(msg1); // not awaited
legacySession.send(msg2); // throws — stream active

// after
for await (const _ of legacySession.stream(msg1)) { /* drain */ }
await legacySession.send(msg2); // previous stream finished
Defensive patterns

Strategy: validation

Validate before calling

// serialize sends through a queue
let sendChain: Promise<unknown> = Promise.resolve();
function queuedSend(session: LegacyAgentSession, payload: AgentSend) {
  const next = sendChain.then(() => session.send(payload));
  sendChain = next.catch(() => {}); // never break the chain
  return next;
}

Try / catch

try {
  await legacySession.send(payload);
} catch (e) {
  if (e instanceof Error && e.message.includes('while a stream is active')) {
    // enqueue the send for after the active stream ends
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Two `send` calls overlap in time: the first triggered `_beginNewStream()` and set `_activeStreamId`, and a second `send` was issued before the first stream's `agent_end` resolved. Also occurs when a caller tries to push an update into a running stream.

Common situations: A UI 'submit' button without debounce allowing double-submits; an orchestration loop that fires follow-up messages without awaiting the prior stream; an event-driven pipeline that reacts to partial output by sending again; mixing the legacy session with code that assumed concurrent send support.

Related errors


AI-assisted analysis of google-gemini/gemini-cli@3c311beac2 (2026-08-12). Data as JSON: /api/errors/298b906d3676af58. Report an issue: GitHub.

Appendix: source

Thrown at packages/core/src/agent/legacy-agent-session.ts:120

    this._subscribers.add(callback);
    return () => {
      this._subscribers.delete(callback);
    };
  }

  async send(payload: AgentSend): Promise<{ streamId: string }> {
    const message = 'message' in payload ? payload.message : undefined;
    if (!message) {
      throw new Error(
        'LegacyAgentSession.send() only supports message sends for the moment.',
      );
    }

    if (this._activeStreamId) {
      // TODO: Interactive may eventually allow selected in-stream sends such as
      // updates or elicitation responses. Keep rejecting all concurrent sends
      // here until we define those correlation semantics.
      throw new Error(
        'LegacyAgentSession.send() cannot be called while a stream is active.',
      );
    }

    this._beginNewStream();
    const streamId = this._translationState.streamId;
    const parts = contentPartsToGeminiParts(message.content);
    const userMessage = this._makeUserMessageEvent(
      message.content,
      message.displayContent,
      payload._meta,
    );

    this._emit([userMessage]);

    this._scheduleRunLoop(parts, message.displayContent);

    return { streamId };

View on GitHub (pinned to 3c311beac2)