Resume session: stream disconnected before completion

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

What version of Codex CLI is running?

v0.116.0

What subscription do you have?

vertex ai key based

Which model were you using?

gpt-5.4

What platform is your computer?

linux

What terminal emulator and version are you using (if applicable)?

bash

What issue are you seeing?

Unable to resume session after few days. I get error:
■ stream disconnected before completion: stream closed before response.completed

Here is what I found

----
When you send include: ["reasoning.encrypted_content"] (codex always does for reasoning models — core/src/client.rs:834), the upstream Responses API returns each reasoning item with an opaque blob:

"encrypted_content": "gAAAAABpxomMi1m..." ← Fernet ciphertext (Python cryptography lib)

The blob is the model's internal reasoning trace — chain-of-thought tokens, hidden state — encrypted with a server-side key. The client cannot read it. The contract is: hold it, send it back on the next turn, and the server decrypts it to give the model continuity of reasoning. This exists so clients can use store: false (no server-side conversation persistence) yet still get reasoning continuity across turns.

Why it works "in‑session" but not "on resume"

Nothing changes on the codex side. What changes is which key is alive on the server. Two ways that key dies:

  1. Snapshot rotation. Today's gateway response identifies the upstream as prod-japaneast-... That's an Azure deployment of OpenAI's gpt-5.4-2026-03-05 snapshot. Azure regularly redeploys with patched snapshots; each new snapshot has its own key set. Blobs encrypted under the old snapshot's key won't decrypt under the new one.
  2. Key TTL / rotation. Even within a single snapshot, the encryption keys are typically bound to a relatively short window (think hours/days — common practice with Fernet keys for forward secrecy). The server rotates keys; old ciphertexts become unreadable.

Your session was created 2026‑03‑27, ~24 days ago. By 2026‑04‑20, at minimum the keys have rotated; very likely the snapshot has also been redeployed at least once. Both effects make the historical encrypted_content blobs un-decryptable now.

Why nothing client-side can "fix" the encryption

The blob is opaque. There is no decryption key on your machine. There is no way to "renew" or "re-encrypt" it — only the original snapshot's server, with the keys that were live at 2026‑03‑27, could have read it. Those keys are gone.

That's why the only options are: drop the encrypted blobs (lose reasoning continuity, keep visible history), or abandon the conversation. There is no third path.

What steps can reproduce the bug?

Try resuming older session when using token based auth.

What is the expected behavior?

Session should continue to work as expected.

Additional information

_No response_

View original on GitHub ↗

3 Comments

github-actions[bot] contributor · 4 months ago

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

  • #17910
  • #17541

Powered by Codex Action

Proview-China · 4 months ago

我应该是找到了一部分问题的来源.

日志里真正关键的是这句:latestTurnStatus=interrupted markedStreaming=true。
也就是说 UI 认为这个线程还有一个“正在流式输出”的旧 turn
但那个流已经断了,所以一直 Reconnecting。我要把这个线程的最后一个坏 turn 状态从前端恢复掉。
...
真正原因钉住了:这个 dev/rebase session 的最后一轮是你点“继续”后
启动的 turn 019db920-f125-7011-ae2c-225b25d2d38f,
但它没有正常写出 assistant 回复和 task_complete,
所以 App 一直认为它还在流式输出,才会 Reconnecting... 2/5。

你可以翻译到英文以查看是否能够解决你的烦恼,或者直接喂给codex让其检查!
这是我让codex为我查看日志检查出来的结果.
而且,我认为我的pro20x会员的gpt-5.4确实拥有更高的速度和智商,上下文漂移的问题也得到了缓解.
还有一点,我的位置在加州,所以我认为oai会在识别我的请求后将其打到一个服务更加优质的地方,我怀疑有这个可能性.
希望可以解决你的问题!
有时在tui中双击esc,回退到最近一条,重新发送,或许能更好的解决你的问题!

Necmttn · 2 months ago

The resume path needs a repair step for stale streaming turn state.

If the rollout says the latest turn is markedStreaming=true but there is no live stream and no response.completed, resume should classify that turn as interrupted, persist the repair, and continue from the last durable event offset. Otherwise the UI keeps trying to reconnect to a stream that cannot exist anymore.

---

_Generated with ax._