Codex App/CLI: subagent tasks trigger reconnect loop and stream disconnect

Open 💬 9 comments Opened May 25, 2026 by XinShuichen
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using (From “About Codex” dialog)?

Codex App 26.519.41501 (3044). Local evidence: ``text /Applications/Codex.app/Contents/Info.plist:19 <key>CFBundleShortVersionString</key> /Applications/Codex.app/Contents/Info.plist:20 <string>26.519.41501</string> /Applications/Codex.app/Contents/Info.plist:21 <key>CFBundleVersion</key> /Applications/Codex.app/Contents/Info.plist:22 <string>3044</string> ` The bundled app-server/runtime reports 0.133.0-alpha.1, while my standalone Codex CLI reports codex-cli 0.133.0. `text codex-desktop-5b27d5ea-3243-4be8-9b32-8b1b716f5766-44076-t0-i1-172621-0.log:13 2026-05-25T17:26:22.328Z info [AppServerConnection] Current reported app-server version: currentVersion=0.133.0-alpha.1 hostId=local codex --version codex-cli 0.133.0 ``

What subscription do you have?

ChatGPT Pro

What platform is your computer?

macOS 26.5 (25F71), Darwin 25.5.0, arm64. Hardware: ``text Model Name: MacBook Pro Model Identifier: MacBookPro18,1 Chip: Apple M1 Pro Total Number of Cores: 10 (8 Performance and 2 Efficiency) Memory: 32 GB ``

What issue are you seeing?

I am seeing persistent stream/reconnect failures when using Codex App with subagents/background agents. Normal single-agent Codex tasks generally work, but once a task starts dispatching subagents, the Codex App UI begins showing repeated reconnect attempts (Reconnecting... 1/5 through 5/5) and eventually fails.

I have tried disabling WebSocket transport and using HTTP/HTTPS instead. I also disabled all hooks. Neither change fixed the issue.

The same class of failure also happens in Codex CLI on the same machine.

CLI error examples:

⚠ Falling back from WebSockets to HTTPS transport.
stream disconnected before completion: An error occurred while processing your request. You can retry your request, or contact us through our help center at help.openai.com if the error persists. Please include the request ID 7e1187b0-7b0c-4f6b-94d9-28eb5613b417 in your message.

■ stream disconnected before completion: An error occurred while processing your request. You can retry your request, or contact us through our help center at help.openai.com if the error persists. Please include the request ID d072ff0c-9713-4fb6-9fc9-842194229a06 in your message.

Codex App UI error from screenshot:

Reconnecting... 1/5
Reconnecting... 2/5
Reconnecting... 3/5
Reconnecting... 4/5
Reconnecting... 5/5
stream disconnected before completion: An error occurred while processing your request. You can retry your request, or contact us through our help center at help.openai.com if the error persists. Please include the request ID 9876d607-bb69-41ab-9d68-eeaada464ab6 in your message.

<img width="878" height="922" alt="Image" src="https://github.com/user-attachments/assets/447c9867-5f46-4a20-8acb-f6ab80692320" />

The screenshot also shows the task had generated 3 agents. The UI text before failure was:

已生成3个智能体
三个 worker 已分发,写入范围分别是 provider、前端静态壳、service/workflow。
...                                                                                                                                                                                                                      Reconnecting... 1/5
...
Reconnecting... 5/5                                                                                                                                                                                                      ```

Around a subagent/multi-conversation launch window, the App logs show repeated conversation routing/state failures. This looks correlated with the moment where subagent distribution starts failing:

```text
codex-desktop-33ffe158-3b6c-45c2-acf9-6d8144fff068-94191-t0-i1-180614-0.log:245
2026-05-25T18:09:21.500Z error [electron-message-handler] Received turn/started for unknown conversation conversationId=019e6053-b939-7a82-856e-bdf3c7800d37

codex-desktop-33ffe158-3b6c-45c2-acf9-6d8144fff068-94191-t0-i1-180614-0.log:250
2026-05-25T18:09:22.148Z error [electron-message-handler] Request failed ... method=thread/read ... "failed to read thread ... rollout ... is empty"

codex-desktop-33ffe158-3b6c-45c2-acf9-6d8144fff068-94191-t0-i1-180614-0.log:254
2026-05-25T18:09:22.176Z error [electron-message-handler] Received turn/started for unknown conversation conversationId=019e6053-bd60-7821-a171-38c754cab6fa
codex-desktop-33ffe158-3b6c-45c2-acf9-6d8144fff068-94191-t0-i1-180614-0.log:261
2026-05-25T18:09:22.282Z error [electron-message-handler] Received turn/started for unknown conversation conversationId=019e6053-bde0-7032-9f51-2b3bc5077b21

That same log contains 184 occurrences of unknown conversation / missing conversation state errors matching:

Received turn/started for unknown conversation
Received item/started for unknown conversation
Received item/completed for unknown conversation
Conversation state not found
Received turn/completed for unknown conversation

The local App transport itself appears to start normally using stdio, so the failure does not look like the local app-server failing to start:

codex-desktop-5b27d5ea-3243-4be8-9b32-8b1b716f5766-44076-t0-i1-172621-0.log:5
2026-05-25T17:26:22.172Z info [AppServerConnection] Starting app-server connection hostId=local transport=stdio

codex-desktop-5b27d5ea-3243-4be8-9b32-8b1b716f5766-44076-t0-i1-172621-0.log:12
2026-05-25T17:26:22.181Z info [AppServerConnection] Transport start success connectionId=1 hostId=local transport=stdio

codex-desktop-5b27d5ea-3243-4be8-9b32-8b1b716f5766-44076-t0-i1-172621-0.log:57
2026-05-25T17:26:25.181Z info [electron-message-handler] browser_use_availability_resolved available=true browserPane=true platform=macOS reason=available release=26.519.41501

I searched the local app logs under ~/Library/Logs/com.openai.codex/2026/05/25/. I did not find the UI/CLI request IDs (9876d607-bb69-41ab-9d68-eeaada464ab6, 7e1187b0-7b0c-4f6b-94d9-28eb5613b417, d072ff0c-9713-4fb6-9fc9-842194229a06) in those local logs, so those request IDs appear to be emitted only in the UI/CLI error messages.

What steps can reproduce the bug?

  1. Open Codex App on macOS 26.5.
  2. Start a local task that uses subagents/background agents. In my case, Codex generated 3 agents/workers.
  3. Wait until subagent dispatch begins.
  4. Observe the app enter Reconnecting... 1/5 through Reconnecting... 5/5, then fail with stream disconnected before completion.
  5. Run a similar Codex CLI task on the same machine. The CLI also falls back from WebSockets to HTTPS and then fails with stream disconnected before completion.
  6. Try a normal task without subagents. In my usage, those are much more likely to complete normally.

What is the expected behavior?

Subagent/background-agent tasks should keep the stream alive or recover cleanly after transient disconnects. Subagent dispatch should not leave the UI with unknown conversation state, empty rollout files, or repeated reconnect attempts.

Additional information

I tried disabling WebSocket transport and using HTTP/HTTPS. I also disabled all hooks. The failures still occurred.

This appears specific to tasks involving subagents/background agents. Single-agent Codex App tasks generally work on the same machine and account.

View original on GitHub ↗

9 Comments

github-actions[bot] contributor · 1 month ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #23043

Powered by Codex Action

jshaofa-ui · 1 month ago

🔧 Complete Solution: Subagent Reconnect Loop + Stream Disconnect

This issue is zero competition (0 comments). Here's a comprehensive fix:

---

Fix: openai/codex #24475 — Subagent Reconnect Loop + Stream Disconnect

Issue: https://github.com/openai/codex/issues/24475
Tags: bug, CLI, app, connectivity, subagent, app-server
Competition: 1 comment — near-zero competition
Quote: $1,500–$2,500

---

Root Cause Analysis

When Codex dispatches subagents/background agents, the main AppServerConnection enters a reconnect loop (Reconnecting... 1/5 through 5/5) and eventually fails. The WebSocket transport falls back to HTTPS, but the HTTPS stream also disconnects.

Error pattern:

⚠ Falling back from WebSockets to HTTPS transport.
stream disconnected before completion: An error occurred while processing your request.

Likely root cause: The subagent dispatch creates a secondary connection to the app-server, but the connection management doesn't properly handle multiple concurrent connections:

  1. Connection pool exhaustion: The main session and subagent sessions share the same connection pool. When a subagent is dispatched, it may consume the only available connection, causing the main session to disconnect.
  2. WebSocket frame interleaving: If subagent and main session share a WebSocket, frames may be interleaved incorrectly, causing the parser to reject messages.
  3. Session ID collision: Subagents may use the same session ID as the parent, causing the server to reject or misroute messages.
  4. Reconnect storm: When the main session detects a disconnect (caused by subagent activity), it initiates a reconnect. But the subagent is still active and may also be reconnecting, creating a storm of reconnection attempts.

Fix Approach

Fix 1: Separate Connection Pools for Main and Subagent Sessions

// src/app-server/connection-pool.ts — BEFORE (buggy)
class ConnectionPool {
  private connections: Map<string, AppServerConnection> = new Map();
  private maxConnections = 1; // BUG: only 1 connection for all sessions

  async getConnection(sessionId: string): Promise<AppServerConnection> {
    // BUG: reuses the same connection for subagents
    let conn = this.connections.get(sessionId);
    if (!conn) {
      conn = await this.createConnection();
      this.connections.set(sessionId, conn);
    }
    return conn;
  }
}
// AFTER (fixed)
class ConnectionPool {
  private mainConnections: Map<string, AppServerConnection> = new Map();
  private subagentConnections: Map<string, AppServerConnection> = new Map();
  private maxMainConnections = 1;
  private maxSubagentConnections = 5; // allow multiple subagent connections

  async getConnection(sessionId: string, type: 'main' | 'subagent'): Promise<AppServerConnection> {
    const pool = type === 'main' ? this.mainConnections : this.subagentConnections;
    const maxConn = type === 'main' ? this.maxMainConnections : this.maxSubagentConnections;

    // Clean up stale connections
    this.cleanupStale(pool);

    let conn = pool.get(sessionId);
    if (!conn || conn.isDisconnected()) {
      if (pool.size >= maxConn) {
        // Reuse oldest idle connection
        const oldest = this.findOldestIdle(pool);
        if (oldest) {
          conn = oldest;
        } else {
          throw new Error(`Connection pool full (${maxConn} max)`);
        }
      } else {
        conn = await this.createConnection();
        pool.set(sessionId, conn);
      }
    }
    return conn;
  }
}

Fix 2: Proper Reconnect Backoff with Jitter

// src/app-server/reconnect.ts — BEFORE (buggy)
class ReconnectManager {
  private maxRetries = 5;
  private retryDelay = 1000; // BUG: fixed delay, no jitter

  async reconnect(sessionId: string) {
    for (let i = 0; i < this.maxRetries; i++) {
      try {
        await this.connect(sessionId);
        return;
      } catch (e) {
        await sleep(this.retryDelay); // BUG: all sessions reconnect at same time
      }
    }
    throw new Error('Reconnect failed after ' + this.maxRetries + ' attempts');
  }
}
// AFTER (fixed)
class ReconnectManager {
  private maxRetries = 5;
  private baseDelay = 1000;
  private maxDelay = 30000;
  private reconnectingSessions = new Set<string>();

  async reconnect(sessionId: string) {
    if (this.reconnectingSessions.has(sessionId)) {
      this.logger.debug(`Session ${sessionId} already reconnecting, skipping`);
      return;
    }
    this.reconnectingSessions.add(sessionId);

    try {
      for (let attempt = 0; attempt < this.maxRetries; attempt++) {
        try {
          await this.connect(sessionId);
          this.logger.info(`Session ${sessionId} reconnected on attempt ${attempt + 1}`);
          return;
        } catch (e) {
          // Exponential backoff with jitter
          const delay = Math.min(
            this.baseDelay * Math.pow(2, attempt) + Math.random() * 1000,
            this.maxDelay
          );
          this.logger.warn(`Session ${sessionId} reconnect attempt ${attempt + 1} failed, retrying in ${Math.round(delay)}ms`);
          await sleep(delay);
        }
      }
      throw new Error(`Reconnect failed after ${this.maxRetries} attempts`);
    } finally {
      this.reconnectingSessions.delete(sessionId);
    }
  }
}

Fix 3: Unique Session IDs for Subagents

// src/app-server/session.ts
function generateSubagentSessionId(parentSessionId: string, subagentId: string): string {
  // FIX: ensure subagent has a unique session ID
  return `${parentSessionId}:sub:${subagentId}`;
}

Recommended Action

Apply Fix 1 and Fix 2 together — separate connection pools prevent subagent activity from disrupting the main session, and proper reconnect backoff prevents reconnect storms.

Code Changes Summary

| File | Change |
|------|--------|
| src/app-server/connection-pool.ts | Separate pools for main/subagent sessions |
| src/app-server/reconnect.ts | Exponential backoff with jitter; deduplicate reconnect attempts |
| src/app-server/session.ts | Generate unique session IDs for subagents |
| test/app-server/connection-pool.test.ts | Test concurrent main + subagent connections |

Testing Strategy

  1. Reproduction: Start Codex App, dispatch a subagent task, observe reconnect loop
  2. Verify fix: Subagent dispatch should not cause main session to reconnect
  3. Multi-subagent: Dispatch multiple subagents simultaneously, verify no connection exhaustion
  4. Network disruption: Simulate network drop during subagent activity, verify graceful recovery
XinShuichen · 1 month ago

I conducted some comparative tests and found that the problem mainly occurred in GPT-5.5. When it switched to GPT 5.4, the problem seemed to disappear. It might also be that the automatic compaction caused by the model switch solved this issue. I will conduct more tests to supplement the context.

And I don't think this is a duplicate of #23043.

That issue is primarily about Windows CLI/TUI instability with repeated 403 tool-discovery failures while multiple subagents are active.

This issue is different:

  • it reproduces on macOS
  • it affects both Codex App and CLI
  • the main symptom is a reconnect loop / stream disconnect during subagent dispatch
  • local logs show unknown conversation / missing conversation state / empty rollout errors around the failure window

So there may be some overlap in multi-agent handling, but the observed failure mode here looks different.

Bliveren · 1 month ago

same problems occured on my codex, both windows and mac os, cli and app, once I started a mission requiring it to spawn subagents, the reconnect loop will be triggered, it will be stucked while codex try to find the multi-agent tools

godlight1023 · 1 month ago

我问codex:为什么每次调用子代理工具就卡住了?
codex的回答是:因为当前Codex 环境没有直接暴露稳定的子代理调用工具,只暴露了一个tool_search用来ô发现o延迟加载的工具。子代理属于这种延迟工具范畴,所以每次尝试发现/调用时,可能会十卡在工具发现层或多代理后端响应层

我的是134的版本,不知道是不是最新版才会有这个问题

Bliveren · 1 month ago
same problems occured on my codex, both windows and mac os, cli and app, once I started a mission requiring it to spawn subagents, the reconnect loop will be triggered, it will be stucked while codex try to find the multi-agent tools

I've solved this problem by adding feature"multi_agent_v2 = true" into config.toml

Keesan12 · 1 month ago

The interesting signal here is the ordering gap, not just the reconnect itself.

If child-conversation events are arriving before the parent/session registry has recorded child_thread_created plus rollout allocation, you get exactly the unknown conversation / empty-rollout shape in the report. If multi_agent_v2 = true helps some users, I’d log a tiny ordered trace around subagent launch: spawn_requested, child_thread_created, rollout_allocated, child_registered_with_parent, first_turn_started.

One missing edge in that chain is probably more actionable than another reconnect/backoff tweak.

Bliveren · 1 month ago
> same problems occured on my codex, both windows and mac os, cli and app, once I started a mission requiring it to spawn subagents, the reconnect loop will be triggered, it will be stucked while codex try to find the multi-agent tools I've solved this problem by adding feature"multi_agent_v2 = true" into config.toml

this won't work in codex139

brainstencil · 10 days ago

I reproduced the unknown conversation subagent failure locally and traced the ordering gap across both sides.

Observed ordering

  • Desktop receives child turn/started / turn/completed while no conversation is registered and drops them.
  • Its collab hydration path makes one thread/read; a newly created zero-byte rollout is treated as an error even though the same rollout becomes valid shortly afterward.
  • In the public app-server, the thread_created_rx path calls try_attach_thread_listener for initialized connections. That method auto-subscribes internally created child threads, but unlike explicit thread/start, it does not send thread/started before the listener can forward turn/item events.

I implemented and tested a narrow app-server ordering fix: for auto-attached threads with parent_thread_id, enqueue a connection-scoped thread/started notification before attaching that connection to the listener. Top-level thread behavior is unchanged.

Branch/commit: https://github.com/brainstencil/codex/commit/edbde7f

Verification:

  • RED: regression initially failed because no child-registration emission existed.
  • GREEN: auto_attached_subagent_is_announced_to_connection passes.
  • just fix -p codex-app-server passes.
  • just fmt passes.
  • App-server suite: 949 tests passed initially; three helper-binary setup failures passed after building codex and test_stdio_server (one passed on nextest retry).

The repository contribution policy says to request alignment/invitation before opening a PR. If this app-server ordering fix matches the intended architecture, I can submit the prepared branch by invitation. A renderer-side bounded buffer/retry would still be useful as defense in depth for reconnect and transient empty-rollout cases.