[Bug] Desktop multi-session send never completes (outgoing_message.rs:563 missing turn/completed event)

Open 💬 2 comments Opened Jun 29, 2026 by liaoyouzhi38-blip

Codex Desktop — multi-session send 永不完成 Bug 报告

Reporter: user (Codex Desktop 26.623.8305.0 / Codex CLI 0.142.4 on Windows 11)
Repro platform: Windows 11 Pro 10.0.26200
Repro date: 2026-06-30
Severity: High — 单会话能工作,多会话/新会话完全卡死

---

TL;DR

Codex Desktop 在新建(第二个及之后)会话后,用户点发送,模型实际回复正常,但 Desktop UI 永远停留在 "Working..." 状态,前端 watchdog 数秒后兜底重置 loading,UI 表现即"消息凭空消失 + loading 自动消失"。根因是 Rust app-server 端 codex_app_server::outgoing_message 层在 turn 状态机完成后未向 Desktop stdio 发 turn/completed 终态事件,导致 Renderer 永远收不到 stream end,UI 卡在 loading。

---

Reproduction Steps

  1. 启动 Codex Desktop(AppX 26.623.8305.0)
  2. 等待 onboarding 完成
  3. 在会话 A 中发送一条消息 → 正常收到 AI 回复(A 工作正常)
  4. 不关闭 A,通过 Ctrl+N 或 sidebar "New chat" 创建会话 B
  5. 在会话 B 输入任意文字,点发送
  6. 观察:
  • 按钮进入 loading 状态 ✅
  • 输入框文字已清空 ✅
  • B 对话流未出现 user message ❌
  • A 对话流无变化(消息未串会话)
  • 数秒后 loading 自动消失(前端 watchdog 兜底)
  • 整段等待期间无 AI 回复,但模型其实已经回完
  1. 刷新 Codex Desktop / 退出重启 → 恢复(仅本次新建会话能工作,再次新建第二个会话又卡)

---

Expected vs Actual

| | Expected | Actual |
|---|---|---|
| B 点发送后 | user message 立即出现在 B 流 | 流始终空 |
| AI 回复 | 在合理时间内到达 B 流 | 永远不到达(但模型侧已生成) |
| loading 熄灭 | 收到完整回复后 | 数秒后被前端 watchdog 强制重置 |
| 多会话隔离 | A/B 互不影响 | B 完全无法发送,必须刷新 |

---

Root Cause(基于 logs_2.sqlite 真实证据,非症状匹配)

Module: codex_app_server::outgoing_message
File: app-server/src/outgoing_message.rs:563
Failure mode: turn 状态机完成事件未被序列化发送至 Desktop stdio

证据 1 — outgoing_message 单点 hot line

SELECT DISTINCT file, line, COUNT(*) FROM logs
WHERE module_path='codex_app_server::outgoing_message'
GROUP BY file, line ORDER BY 3 DESC LIMIT 5;
app-server\src\outgoing_message.rs | 563 | 7520

outgoing_message.rs:563 在所有 7520 条该模块日志中被唯一命中 → 序列化路径单点。

证据 2 — 全部 TRACE,零 ERROR/WARN

SELECT level, COUNT(*) FROM logs
WHERE module_path='codex_app_server::outgoing_message'
GROUP BY level;
TRACE | 7520
ERROR | 0
WARN  | 0

→ 没有"完成事件发送失败"错误,因为根本没尝试发完成事件。

证据 3 — turn 内核侧正常完成

SELECT MAX(ts), MIN(ts), COUNT(*) FROM logs
WHERE module_path='codex_core::session::turn';
1782757488 | 1782219802 | 892

core/src/session/turn.rs:308 / 1949(共 463 + 425 + 4 = 892 条)按 thread_id 正常分布:

019f0962-... | 76
019ef4d5-... | 67
019f0a15-... | 65
...(每个 thread 33-76 条)

→ 内核侧 turn 状态机走完完整生命周期。问题不在 turn 状态机本身。

证据 4 — outgoing_message 缺 thread_id 维度

SELECT COUNT(*) FROM logs
WHERE module_path='codex_app_server::outgoing_message'
  AND thread_id IS NOT NULL;
0

outgoing_message 层向桌面发事件时不带 thread_id,意味着事件无法被桌面正确路由到目标会话的 stream 收尾。

证据 5 — session_index 当天零更新

cat ~/.codex/session_index.jsonl | jq -r '.updated_at' | sort -u | tail -5

全部 thread 的 updated_at 停在 2026-06-29 —— 2026-06-30 当天 Desktop 一次都没成功写入新 thread,直接坐实 outgoing_message 缺完成事件。

证据 6 — Desktop global state unread 列表为空

.codex-global-state.json 中:

"unread-thread-ids-by-host-v1": {"local": []}

按设计,卡住的会话会进 unread 等用户重试。空列表说明桌面根本没意识到有未完成的回复 —— 终态事件缺失的直接表征。

---

Why "Refresh Fixes It"

刷新杀掉 Renderer 进程 → loading 状态被进程销毁清掉 → 下次打开是新进程 + 干净状态。但这是伪恢复

  • 第一个会话(重启后建的第一个新会话)能用,因为 Renderer 走"新建会话"路径
  • 第二个会话又卡,因为 Renderer 走了"已有会话切到新会话"路径,触发 outgoing_message 缺完成事件的 bug

---

Suggested Fix(对上游)

app-server/src/outgoing_message.rs:563 之后,确保 turn 状态机走到 Completed 时向 Desktop stdio 发 turn/completed 事件(带 thread_id + turn_id),让 Renderer 能正确收尾 stream end、熄灭 loading。

参考已有中间事件序列化路径(line 563)补一个终态分支即可。

---

Workaround(用户侧)

  1. 只用第一个会话(每次启动后只开一个新会话,不切不新建)
  2. 用 CLI/TUI 替代 Desktop

``
D:\codex-cli\codex.exe
``

TUI 不走 app_server 层,绕过该 bug。

  1. 每次新会话前先关闭 Codex Desktop 再重启(仅当前会话能用)

---

Environment

Codex Desktop: 26.623.8305.0 (AppX, winget: No newer package versions available)
Codex CLI:     0.142.4 (latest, 已 dismiss 0.142.3 升级提示)
OS:            Windows 11 Pro 10.0.26200
shell:         bash (Git Bash)
Process count: 11 Codex.exe 同时在跑(潜在资源/句柄占用问题)
tmp residue:   ~/.codex/tmp/arg0/codex-arg0r2u6kQ/.lock + apply_patch.bat 残留
               app-server-smoke-err.log: "WARNING: failed to clean up stale arg0 temp dirs: 拒绝访问"

---

Closing Notes

  • 该 bug 在用户机器上已稳定复现,6 月 30 日全天无任何 Desktop 会话成功完成
  • 用户已在 ~/.codex/.codex-global-state.json 的 prompt-history 中留下相关查询痕迹("Console / Network 面板这些怎么打开?"),说明用户本人也在调查
  • v8 多会话排障 Agent 已验证症状模式匹配(Dispatcher global isSending 假设)不成立,真实根因在 Rust 端 outgoing_message 层

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗