[Windows App 26.820.7780.0] Composer stays disabled after the first completed turn in a new task

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

Environment

  • Codex Desktop package: OpenAI.Codex 26.820.7780.0
  • Bundled app server: codex-cli 0.150.0-alpha.8
  • Platform: Windows x64, OS version 10.0.26200 (build 26200.9168, 25H2)
  • Task target: Local, projectless workspace
  • Shell: PowerShell
  • Model in the captured occurrence: gpt-5.6-sol, reasoning effort xhigh
  • Approximate occurrence time: 2026-08-26 19:29, UTC+08:00

Task IDs, local paths, account details, and prompt contents are omitted for privacy.

Preconditions

  1. The user had deleted all conversations visible in the UI before testing.
  2. Codex Desktop was running normally and could create a new local task.
  3. No approval dialog was open or pending.
  4. The first prompt was short plaintext with no attachment.

Deleting the visible conversations did not make the local Codex state empty. A later read-only inspection still found a substantial local thread index. That is an observation and a possible amplifier, not a confirmed cause.

Minimal reproduction

  1. Open Codex Desktop on Windows.
  2. Create a new local task.
  3. Send a short plaintext first message.
  4. Wait for the assistant response to finish rendering.
  5. Type a short second plaintext message in the composer.
  6. Attempt to send it.

Actual result

The second message remains in the composer and cannot be submitted. The Send button stays disabled/grey even though the first turn has already completed.

For the captured occurrence:

  • the assistant response was fully generated;
  • the rollout transcript ended with an authoritative task_complete event;
  • the task index later reported the task as idle;
  • nevertheless, the visible composer remained locked.

This appears to be a Desktop UI / local state synchronization failure. The available evidence does not establish the underlying root cause.

Expected result

After the first turn reaches its terminal completed/idle state:

  • the composer should become enabled;
  • the second message should produce a new turn/start;
  • if state reconciliation fails, the app should show an actionable error and provide a recovery action instead of leaving the composer disabled indefinitely.

Frequency

The user reports that this occurs on the second message in every new task attempted after deleting all visible conversations.

One occurrence was correlated precisely with local logs and the rollout transcript. The report does not claim a fully automated deterministic reproduction.

Captured timeline and logs

The affected task was created at approximately 19:28:54.

19:29:02  first turn_input submitted
19:29:09  assistant message output completed
19:29:10  post-sampling state:
          full_context_window_limit_reached=false
          token_limit_reached=false
          model_needs_follow_up=false
          has_pending_input=false
          needs_follow_up=false

The rollout was small (16 records, approximately 136 KB) and ended with:

event_msg task_complete

The task index subsequently reported the affected task as idle.

Two transport warnings occurred during startup/turn preparation:

startup websocket prewarm setup failed:
stream disconnected before completion: tls handshake eof

incremental request failed:
websocket reuse properties didn't match

The response still completed after these warnings, so they are included as correlation only and are not claimed as the cause.

At app startup, the local app-server also emitted repeated thread-index reconciliation warnings:

state db list_threads returned stale rollout path
state db discrepancy during list_threads_db: stale_db_path_retained

A read-only local maintenance report found:

active thread rows: 136
active title characters: 3,791,975
active first_user_message characters: 3,792,320
maximum title / first_user_message length: 77,059
titles over configured limit: 114
first_user_message values over configured limit: 113
first_user_message values over 10k characters: 109
metadata repair candidates: 115
active rollout size: 1.781 GB
archived rollout size: 68.178 GB
current log size: 10.6 MB

This metadata/index bloat may increase the likelihood of a renderer or reconciliation failure, but it has not yet been repaired and A/B tested, so it is not a confirmed root cause.

Items already ruled out or localized

  • First-turn model/backend failure: ruled out for the captured occurrence; the assistant reply and task_complete were persisted.
  • Turn still legitimately active: ruled out by task_complete, no pending input/follow-up flags, and the later idle task status.
  • Context/token exhaustion: the captured log explicitly reports both context and token limits as not reached.
  • Approval wait: no approval request was present; the task used a no-approval/full-access profile.
  • Oversized current conversation: the affected new task contained only 16 rollout records and was approximately 136 KB.
  • Large current log database: the active log database was only approximately 10.6 MB.
  • Optional MCP startup failures: unavailable optional MCP servers were omitted for the affected turn and the thread was created with zero dynamic tools. Earlier MCP connection errors therefore do not establish the cause of this composer lock.

Temporary recovery / workarounds

  • Fully quitting and relaunching Codex causes the persisted task to be recognized as idle again.
  • This is only a partial workaround: the user reports that the same second-message failure returns in new tasks.
  • Starting another new task and deleting visible chat history did not resolve the problem.
  • A local thread-metadata repair has been proposed but not yet executed, so it should not be treated as a verified workaround.

Possibly related issues

  • #40794 — same app version and a second manual-message freeze, but that report requires cross-task message injection and localizes the failed click before turn/start.
  • #14251 — composer remains disabled after an interrupted turn, but that case is missing task_complete; this occurrence has a valid terminal event.
  • #32982 — the inverse timing race, where the composer enables before authoritative turn completion.
  • #21211 — unbounded thread metadata and eager history hydration.
  • #24263 — Desktop renderer/turn-state reconciliation failures.

Sanitized structural logs can be provided if maintainers need additional detail.

View original on GitHub ↗

2 Comments

github-actions[bot] contributor · 1 day ago

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

  • #39692
  • #39513

Powered by Codex Action

ashjo42 · 4 hours ago

Follow-up: clean-profile A/B result and a working recovery path

I completed a clean-profile recovery after filing this issue. The second-message lock no longer reproduces in the clean profile: the app has since accepted second and later messages in long-running local tasks.

What changed

The important step was not merely reinstalling the Windows package. This installation used a custom CODEX_HOME, so an uninstall/reinstall would otherwise reopen the same persisted state.

The recovery procedure was:

  1. Fully quit Codex.
  2. Back up and rename/isolate the actual custom CODEX_HOME; create a new empty home.
  3. Reinstall and sign in.
  4. Before restoring anything, create a new local task and verify at least two consecutive turns.
  5. Restore only user-facing preferences and portable configuration: AGENTS.md, keybindings, selected settings, user skills, project mappings, and selected memory summaries.
  6. Do not copy back the old state_5.sqlite, thread_history_1.sqlite, queue database, WAL/SHM files, logs, caches, WebView profile, locks, or old MCP/plugin runtime state.
  7. Keep old conversations as backed-up raw rollout JSONL plus readable Markdown. For important unfinished work, create small project-local handoff documents and continue them in fresh tasks instead of restoring the whole old index.

The live personal-profile restore manifest explicitly excluded all session/index databases and runtime security/policy state. The old profile and raw conversations remain preserved; nothing was deleted.

Additional evidence

This gives a useful A/B localization:

  • Old persisted profile: second message consistently remained disabled even though the rollout ended in task_complete and the indexed task later became idle.
  • New empty profile using the same account/workstation: second and later messages work.
  • Restoring portable preferences/skills without restoring the old session databases did not bring the lock back.
  • The old SQLite databases passed PRAGMA quick_check, so this does not look like ordinary SQLite page corruption. It is still consistent with stale cross-file paths, oversized metadata, invalid derived projection offsets, or renderer/app-server reconciliation state.

I also validated a conservative selective-restore procedure in an isolated sandbox:

  • human top-level threads only;
  • per-rollout limit of 10 MiB;
  • 131 threads selected, including 50 imported from the retained index;
  • 77 oversized threads and 2 missing rollouts skipped;
  • approximately 196 MB of selected rollouts;
  • old WebView state, the old ~1.82 GB history database, queue, logs, caches, subagent threads, and MCP/plugin runtime config excluded;
  • imported rollouts checked against derived history projection byte offsets; stale/out-of-range projections are discarded and rebuilt from the authoritative JSONL rather than modifying the raw conversation.

That sandbox test is evidence that bounded selective recovery is feasible, but it is not evidence that the 10 MiB threshold is the root-cause boundary.

Working user-side workaround

For affected users with a custom CODEX_HOME, the reliable recovery sequence is currently:

  • preserve and isolate the old home;
  • start with an empty home;
  • test two turns before restoring data;
  • restore portable configuration separately;
  • do not restore the old session/index/WebView/cache state as a unit;
  • use exported transcripts or small handoffs for unfinished conversations.

This is a recovery procedure, not a confirmed root-cause fix, and it should not be treated as an officially supported database migration.

Possible product-side fixes

  1. Reconcile composer enablement from the authoritative turn terminal state. A persisted task_complete / server idle state should not remain blocked by stale renderer or thread-list state.
  2. If reconciliation fails, show an actionable error and offer a safe “reload/repair local task state” action instead of leaving Send disabled.
  3. Bound/sanitize title and first_user_message metadata during ingestion and avoid eagerly hydrating multi-megabyte metadata into thread-list/UI state.
  4. Treat stale rollout paths and invalid projection offsets as rebuildable derived-state failures. Preserve authoritative rollout JSONL and invalidate/rebuild the derived index entry.
  5. Detect when reinstalling still points at a large pre-existing custom CODEX_HOME, and warn before automatically reopening it.
  6. Provide a supported selective-import path for conversations that keeps raw rollouts but excludes caches, WebView state, queues, and obsolete derived databases.

The clean-profile A/B makes old persisted local state a much stronger suspect, but it still does not identify one specific table, path, or metadata field as the root cause.