[Bug Report]: Streaming startup failure leaves exclusive Agent Server busy

Author: dajiaohuangCreated Aug 22, 2026Updated Aug 22, 2026

Version

Current main at c2ad42e3eb9b27830db41a3e6f51ca7179d9b168 (@tarko/agent-server / @tarko/agent-server-next).

Issue Type

  • Agent TARS Server (@tarko/agent-server)

Model Provider

Provider-independent. Any agent whose streaming run() rejects before returning an AsyncIterable can trigger it.

Problem Description

In exclusive mode, a streaming query that fails while starting leaves the server's running-session slot occupied. Subsequent requests are then rejected as busy even though no stream is running.

The same control flow exists in both server implementations:

  • multimodal/tarko/agent-server/src/core/AgentSession.ts, runQueryStreaming()
  • multimodal/tarko/agent-server-next/src/services/session/AgentSession.ts, runQueryStreaming()

The sequence is:

  1. setRunningSession(this.id) marks the exclusive slot busy.
  2. await this.agent.run(runOptions) rejects before returning a stream.
  3. The catch block returns createErrorEventStream(handledError).
  4. clearRunningSession() only exists in wrapStreamForExclusiveMode() for a successfully returned stream, so the synthetic error stream never releases the slot.
  5. canAcceptNewRequest() continues to return false until unrelated cleanup or abort logic happens.

Minimal provider-free reproduction with a fake agent/server:

typescript
const server = createExclusiveServerStub();
const session = createSession(server, {
  run: async () => {
    throw new Error('startup failed');
  },
});

const errorStream = await session.runQueryStreaming({ input: 'test' });
for await (const _event of errorStream) {}

expect(server.getRunningSessionId()).toBeNull(); // actual: session id remains set
expect(server.canAcceptNewRequest()).toBe(true); // actual: false

Expected: after the startup failure has been converted to its error stream, the exclusive slot is released according to a documented lifecycle rule.

Actual: the failed session remains the running session and blocks unrelated later requests.

Impact: a transient model/configuration/agent initialization error can wedge an exclusive Agent Server until manual cleanup or restart. Both the current and agent-server-next implementations contain the same path.

This is issue-only for now because a complete fix needs the maintainers to choose whether the exclusive slot is released immediately when agent.run() rejects or only after the caller consumes/closes the synthetic error stream, and the behavior must remain consistent across both server generations and their HTTP/SSE lifecycle. Regression coverage should exercise rejection before stream creation, partial/abandoned consumption of the error stream, and a subsequent request in exclusive mode.

Error Logs

Representative observable state after a rejected streaming start:

runningSessionId: <failed session id>
canAcceptNewRequest(): false
active stream: none

Source: bytedance/UI-TARS-desktop