[macOS Desktop] Reboot can switch app-server runtime and wedge paginated history at a duplicate ordinal
Environment
- OS:
Darwin 27.0.0 arm64 arm(macOS) - Codex Desktop:
26.818.41509(build6962) - Bundled CLI:
codex-cli 0.149.0-alpha.4.1 - Local Desktop thread history mode:
paginated
Summary
After a normal macOS restart, Codex Desktop can reopen a paginated thread with an older
conversation snapshot, stop responding, or fail to recover it. The canonical rollout JSONL
still contains the newer turns, but the Desktop history projection stops advancing and the UI
serves stale history.
This is not limited to a single missing file. The observed failure is a restart/login bootstrap
race: the app-server runtime selected before reboot is not guaranteed to be the runtime selected
after reboot. When the second runtime resumes the same paginated rollout, it can write a record
with an ordinal already used by the previous runtime. The projection then waits for the next
ordinal forever.
Observed errors
Depending on which action is attempted, the Desktop UI shows variants of:
failed to resolve rollout path ... file does not existno rollout found for thread id ...invalid paginated history lineage ... missing source rollout恢复对话失败(conversation recovery failed)
In another affected state, the thread remains on “thinking” without producing a response, and
retrying reports that the session is already open in another application.
Reproduction timeline
- Start a long-running local paginated Desktop thread and let it write multiple turns.
- Leave the thread's rollout and state databases intact.
- Restart macOS normally.
- Launch Codex Desktop and open/continue the same thread.
- Observe that the Desktop app-server may be launched from a different runtime than before
reboot. The resumed rollout can contain a duplicate ordinal (for example, a valid record at
ordinal N before reboot and a different thread_settings_applied record at the same ordinal
N after reboot).
- The projection cursor remains at the earlier boundary (expected
N+1), while the raw rollout
continues to grow. Opening the thread shows older history and follow-up/retry may fail.
The same class of failure is likely when switching accounts or otherwise rebuilding the GUI
session, although the clean-restart path above is the independently verified reproduction.
Evidence from one affected thread
- The raw rollout remained newline-valid and sequential through the latest completed turn after
recovery; no conversation content was deleted.
- Before reboot, the patched app-server wrote a valid
token_countrecord at ordinal3588. - After reboot, the official Desktop app-server wrote
thread_settings_appliedat ordinal3588
in the same logical thread.
- The SQLite projection then stopped at the duplicate boundary and the UI remained behind the
raw rollout.
- Reinstalling or reopening the app did not reconcile the projection automatically.
All identifiers, absolute paths, credentials, and conversation content are intentionally omitted.
Expected behavior
- Desktop should select a deterministic, version-compatible app-server runtime across login,
reboot, and GUI-session reconstruction; a later process must not append duplicate paginated
ordinals to an existing rollout.
- On startup and thread open,
thread_history_*should be treated as a rebuildable projection:
detect ordinal/byte-offset mismatches, reconcile it from the canonical rollout, and advance it
to the durable end instead of silently freezing.
- If a source rollout truly is missing, recovery should report a precise actionable error and
avoid leaving a ghost/stale thread that appears present but cannot continue.
- A follow-up should either be durably persisted and start a response, or return an explicit
dispatch failure; it must not appear successful while leaving the thread unchanged.
Impact
Users see several completed rounds disappear from the visible conversation, cannot continue the
latest turn, and may retry against an old context. This is especially damaging for long-running
tasks because the durable record and the UI disagree without a clear recovery path.
Related reports
- #35746 — paginated history drops valid rollout records and reuses ordinals
- #38792 — desynchronized projection cursors are never repaired on resume
- #40112 — Desktop shows stale pre-crash state after restart while durable history is intact
- #40109 — concurrent rollout writers can assign duplicate paginated ordinals
Please consider a startup reconciliation/doctor path and a regression test that exercises a normal
macOS reboot (or GUI-session rebuild) before and after resuming the same paginated thread.
9 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Cross-OS confirmation: the same duplicate-ordinal boundary appears in Windows history after restart (token_count followed by thread_settings_applied at N). The canonical JSONL remains intact while the paginated projection wedges, so repair needs durable-rollout preservation plus a thread_history cursor parity check. Related: #35746, #40109, and #38792.
Windows confirmation of the same duplicate-ordinal boundary, observed after an authentication/session rebuild.
Environment
19045, x6426.818.41509history_mode = paginatedUTC+09:00)User-visible impact
After the repeated
refresh_token_invalidatedsign-in loop, quitting and reopening Codex Desktop causes previously visible conversation history to disappear from the UI. During a running process, the affected long thread can continue receiving new turns, but the durable history projection does not advance.Read-only validation: the conversations were not deleted
A read-only inspection found:
missing_candidate = 0okThere is also a catalog/selection inconsistency after reauthentication: the globally selected remote-host value matches 0 of the 2 hosts registered in the local catalog, while 33 legacy global project-thread assignments point to the selected project but all 63 current user-thread/catalog rows have a null
project_id. This may help explain the empty sidebar, but it is reported as an observation rather than a proven cause.Exact duplicate-ordinal evidence from the affected paginated thread
At a read-only snapshot:
105,667,652bytes11,645011643591occurs exactly twice, consecutively:event_msg / token_count, ordinal591event_msg / thread_settings_applied, ordinal591next_rollout_byte_offset = 6502760next_rollout_ordinal = 59259111643The live writer repeatedly reports:
This same error was recorded at least 542 times across 3 distinct Desktop/app-server processes, so reopening the app does not reconcile or repair the projection.
The first projection failure began on 2026-08-22 at 21:10 KST, after the 20:28–20:38 KST authentication loop. That establishes temporal correlation only; it does not prove authentication caused the duplicate ordinal.
Expected behavior
No identifiers, credentials, conversation text, filenames, absolute paths, email addresses, request IDs, account IDs, thread IDs, or raw log/database files are included.
Additional read-only follow-up narrows both the likely mechanism and the scope of the Windows instance reported above.
Exact
#35746fingerprint and handoff timelineThe first ordinal-
591record is not merely a generictoken_count: itsrate_limits, nestedprimary, andcreditsfields are all populated structured maps (values intentionally omitted). This exactly matches the resume-tail record fingerprint described in #35746.The duplicate appears 15m46.743s after the structured
token_count. Records immediately before and after this boundary increase normally.Process attribution cannot be proven from the JSONL because rollout records do not carry a process UUID. The logs nevertheless show a strong handoff signal: the process active for the first
token_countstopped logging, a different app-server process issuedthread/resumeabout 5m52s before the duplicate, and only the newer process overlaps the second record's time window. This is consistent with a cross-process resume, but it is not proof that two writers appended concurrently.The last authentication-manager
401 refresh_token_invalidatedoccurred about 9m30s before the duplicate. The auth error preceded the observed resume/handoff boundary; the logs do not establish that it caused the handoff or ordinal reuse. The first projection failure surfaced later and therefore did not create the already-present duplicate.Local-inventory negative control
At the initial full-scan snapshot, I parsed all 47 available user-created uncompressed rollout JSONL files, totaling 134,967 physical records:
000591boundary aboveThe cursor reported above lands at the exact start of the second
591. In a later snapshot ending immediately after ordinal11,998(record timestamp2026-08-23 10:04:10.214Z), the derived projection was behind by the replayed591plus 11,407 later ordinal values (592through11,998): 11,408 unprojected physical records and100,709,536bytes.This single duplicated ordinal explains the permanently stale projection for one long paginated thread. It cannot by itself explain why all 63 intact local threads disappeared from the Desktop sidebar after reauthentication. The selected-host/project catalog mismatch reported above remains a separate unresolved sidebar/catalog observation; causality is not established.
No field values, credentials, identifiers, paths, conversation content, repository data, or raw files are included.
Additional cross-platform evidence from Windows Codex Desktop
26.818.8289.0, bundled app-server0.149.0-alpha.4.3.The same paginated projection failure occurred during app-server reconnect: the cursor expected the next ordinal but read a duplicate of the previous ordinal from the canonical JSONL. I found this in 12 local rollouts. A backup-first repair advanced only projection byte offsets past the duplicate metadata records, preserved all raw rollouts, passed SQLite integrity checks, and restored a clean app-server reconnect.
This confirms the startup reconciliation behavior described here is also needed on Windows, and that a rebuildable projection should recover automatically instead of terminating the app-server with
0xFFFFFFFF.Additional macOS reproduction on a newer build; sequential resume narrows the likely seam
This is a sanitized corroborating observation for #40178, not a separate failure class.
Environment
26.5, arm6426.818.61809(build7019)0.149.0-alpha.4.3paginatedObserved sequence
event_msg/token_countrecord at ordinalN. A type-only inspection confirmed populatedrate_limitsdata and a numericprimary.used_percent; all values are omitted.thread/resumecompleted for the affected paginated thread.event_msg/thread_settings_appliedat ordinalN, followed immediately byevent_msg/task_startedatN+1.Nboundary.expected ordinal N+1, got N; newer durable records remained beyond that boundary while the visible projection stayed stale.I did not find evidence that proves two writers overlapped in this reproduction. The timing is consistent with a sequential process handoff/resume, so concurrent append alone may not be necessary to trigger the fault.
Source-level hypothesis, not a claim about the installed binary
In current public source at commit
7c6eb0e:scan_next::<RolloutLine>(): ordinal.rs;next_ordinal: thread_history_materialization.rs;This makes the #35746 tail-decoding path the leading source-level hypothesis: if a valid top-level ordinal exists but the full trailing payload is skipped during resume-tail decoding, the resumed recorder can seed from an earlier record and reuse
N. The structured rate-limit fingerprint strengthens that match, but this source inspection still does not prove that the installed Desktop binary executed that exact path.Requested OpenAI guidance
0.149.0-alpha.4.3implementation?doctoror repair path for an already-written different-content ordinal collision that preserves the durable rollout, and should the normal projector fail closed rather than skip either record?Suggested regression: a structured
token_count(N)tail followed by a cold sequential resume must append atN+1; a different-content collision must fail closed without discarding the last readable projection.Related: #35746, #38792, and #40109.
Claim boundary: this is one sanitized corroborating observation plus public-source analysis. It does not prove universal scope, data deletion, the exact installed-binary control flow, or that any proposed fix is already available.
Disclosure: this comment was prepared with Codex assistance at the account owner's request. No raw history, identifiers, local paths, credentials, or conversation content are included.
Follow-up: repeated macOS reproduction and a failed self-hosted recovery path
No conversation content, full thread identifiers, absolute local paths, credentials, or account information are included below.
Environment:
Read-only audit:
expected ordinal N, got N-1/N-2signature.Current-build behavior:
migrate-rolloutsdo not advance the frozen cursors.Recovery-path finding:
An agent running inside the Desktop app cannot reliably perform the required offline recovery of the same app. Closing Desktop interrupts the hosting agent and its app-server; attempts to hand the repair to a detached local helper did not obtain a stable offline interval and were stopped without modifying any rollout or projection database. This is an architectural dead end for ordinary users, not a viable support procedure.
The product therefore needs a supported recovery path that does not depend on an agent modifying its own live storage:
thread_items,thread_turns, and projection state transactionally from the durable rollout.codex doctor --repair-historyor equivalent UI action.thread_settings_applied, and subagent rollouts.The local canonical records remain preserved for a private diagnostic channel if maintainers request specific sanitized fields. No public raw transcript or database upload will be made.
Windows appendix: isolated recovery reaches the complete durable history
This is a sanitized corroborating case for the same failure class, with an isolated recovery validation. No project/repository name, local path, thread ID, title, prompt, response text, credential, account identifier, or raw database/log file is included.
Environment and impact
26.820.7780.00.150.0-alpha.80.149.0-alpha.4.1paginatedThe durable rollout continued receiving valid turns through the current day, while Desktop remained frozen at the history visible around the duplicate boundary. Restarting Desktop did not change the visible cutoff.
Read-only evidence
event_msg/token_count(N)event_msg/thread_settings_applied(N)event_msg/task_started(N+1)Nrecord while expectingN+1.okexpected ordinal N+1, got Nprojection failure 435 times; each later append retried and failed at the unchanged boundary.This confirms that the later history was not deleted. The user-visible truncation is the stale derived projection.
Isolated recovery validation
I made private local copies using a SQLite online backup and a byte-for-byte rollout copy. In the copies only, I conditionally advanced the affected projection byte offset past the duplicate
thread_settings_applied(N)record while retaining the expected next ordinalN+1. The durable rollout itself was not edited.After starting the current
0.150.0-alpha.8app-server and resuming the copied thread:thread/turns/list;ok;The live installation was not modified.
This specific skip is narrow:
thread_settings_appliedproduces no projected turn/item change in the current projection mapping, and the isolated replay confirmed no loss of later materialized history. A generic “delete and rebuild projection rows” repair would still encounter the duplicate ordinal unless rebuild/reconciliation explicitly handles the collision.Product implication
The affected thread is recoverable, but ordinary users need a supported offline/startup repair path. A safe implementation could detect when the cursor lands on a duplicate projection-neutral metadata record, preserve the canonical rollout and old readable projection, rebuild or advance transactionally, validate the replacement, and only then publish it. The UI should also surface projection lag instead of presenting the stale history as complete.
Disclosure: this appendix was prepared and submitted with Codex assistance at the account owner's request.
Sanitized macOS Remote confirmation and recovery result from a MacBook Pro host controlled through another Mac.
Environment:
Exact boundary:
Backup-first recovery:
Result:
This independently confirms the same narrow recovery shape reported in #41079 and reinforces the need for automatic duplicate-boundary reconciliation plus a supported doctor/repair command. No thread IDs, absolute project paths, prompts, conversation content, credentials, or raw logs are included.