Skip to content

Desktop: "Error submitting message" — turn/start times out (30s) while app-server sidecar stalls silently for minutes #27395

Open

Description

@malikdraz

What version of the Codex App are you using?

26.608.12217 (codex core 0.138.0-alpha.7, originator Codex_Desktop, auth mode ChatGPT)

What subscription do you have?

What platform is your computer?

macOS 26.5.1, Apple Silicon (arm64)

What issue are you seeing?

Submitting a message in a Desktop thread intermittently fails with the inline banner "Error submitting message". Re-sending the exact same message a minute or two later succeeds.

Desktop renderer log shows the composer giving up after a 30-second RPC timeout on turn/start:

2026-06-10T13:05:09.164Z warning [electron-message-handler] mcp_request_timeout
    conversationId=019eb19c-84da-7933-a03c-cbfbb4e11d57 method=turn/start
    pendingCount=13 requestId=654d3396-... timeoutMs=30000
2026-06-10T13:05:09.173Z error [electron-message-handler] [Composer] submit failed
    cwd=~/Documents/Codex/2026-06-10/... errorMessage=Timeout errorName=Error
    errorStack="Error: Timeout\n at Object.error (app://-/assets/vscode-api-....js:...)\n at ks (app://-/assets/composer-....js:...)" followUp=local mode=local

7 occurrences on 2026-06-10 (first at 10:48:42Z), zero occurrences in the preceding 13 days of desktop logs. All 7 timeouts are method=turn/start; pendingCount grows across the day (2 → 5 → 6 → 13), so requests pile up against the same app-server sidecar.

Root-cause evidence from the app-server side (~/.codex/logs_2.sqlite, logs table): the main app-server sidecar process stops emitting any log rows at all for multiple minutes, and every submit failure falls inside one of those silent windows. Example: the sidecar wrote ~1000 rows during 23:04 local while a turn was streaming, then wrote nothing from 23:05 through 23:11 — exactly bracketing three consecutive submit timeouts at 23:05:09, 23:06:50 and 23:10:33 (UTC+10 local; 13:05/13:06/13:10Z in the desktop log above).

The stalled thread's previous turn never finalizes: e.g. thread 019eb19b-dae6-7192-be60-8d0432f9587c logged its final answer and token usage at 12:57:27Z (needs_follow_up=false has_pending_input=false), then the thread never logged another line and never emitted turn/completed; the next turn/start for that thread (12:57:44Z) timed out at 12:58:14Z. The desktop also logs Received turn/started for unknown conversation for the ephemeral title-generation thread during the same window.

Possibly relevant: the stall windows coincided with elevated concurrency on the shared ~/.codex SQLite databases — 3–4 distinct codex processes (per process_uuid in the logs table) writing to logs_2.sqlite at the failure minutes vs. 1 normally (nested codex exec runs spawned by an agent, plus agent turns querying ~/.codex/state_5.sqlite / logs_2.sqlite directly). logs_2.sqlite had grown to 1.4 GB with a multi-MB WAL.

Ruled out locally: plugin hooks (UserPromptSubmit/Stop hook binaries exit in <1 s when run by hand), the notify turn-ended client (unchanged binary), network-proxy feature (same log lines appear on prior, healthy days), leftover nested codex processes (none running; only the sidecar holds the DBs), and a newly added <name>.config.toml profile-v2 file (never loaded without --profile).

What steps can reproduce the bug?

Not deterministic, but reliably reproduced today with this pattern:

  1. Run an agent thread in the Desktop app that heavily reads ~/.codex itself (e.g. SQLite queries against a large logs_2.sqlite, rg over ~/.codex) and/or spawns nested codex exec / codex --profile <name> exec subprocesses, so several codex processes share the ~/.codex SQLite databases concurrently.
  2. While that turn is running (or just after its final answer), submit another message — either a follow-up in the same thread or a message in another thread owned by the same sidecar.
  3. If the sidecar is in one of its silent stall windows, the submit shows "Error submitting message" after ~30 s.
  4. Wait 1–5 minutes; resubmitting the identical message succeeds.

Affected thread/session ids from 2026-06-10 (in case server-side lookup helps):
019eb122-5dbf-7462-ac2d-a0ea9ac9a39f, 019eb12c-1a8d-7551-990f-768161dd4a28, 019eb12d-befb-71e0-88c2-e77aaeefc885, 019eb19b-dae6-7192-be60-8d0432f9587c, 019eb19c-84da-7933-a03c-cbfbb4e11d57

What is the expected behavior?

  • turn/start should be acknowledged promptly (or fail fast with a real error) even when the thread's previous turn is still finalizing or the sidecar is under I/O pressure; a queued/steered message should not surface a generic "Error submitting message".
  • A turn that has produced its final answer should always reach turn/completed; the per-thread session loop should not wedge silently with no log output.
  • Consider rotating/pruning logs_2.sqlite — unbounded growth (1.4 GB here) amplifies any DB-contention stall.

Additional information

  • Timezone note: desktop log timestamps are UTC; app-server sqlite analysis above is local (UTC+10).
  • Happy to provide redacted log excerpts or run diagnostics on request.

Activity

  1. added
    bugSomething isn't working
    appIssues related to the Codex desktop app
    app-serverIssues involving app server protocol or interfaces
    on Jun 10, 2026
  2. twentyOne2x commented on Jun 11, 2026

    @twentyOne2x

    Adding a current-build datapoint that matches this issue and links it to broader Desktop live-state degradation: #27601.

    Environment:

    Codex Desktop 26.608.12217 / build 3722
    Bundled CLI 0.138.0-alpha.7
    macOS 26.3 / Darwin 25.3.0 arm64
    

    Observed repeated turn/start timeouts while submitting a message in Desktop:

    mcp_request_timeout method=turn/start pendingCount=86 timeoutMs=30000
    mcp_request_timeout method=turn/start pendingCount=87 timeoutMs=30000
    mcp_request_timeout method=turn/start pendingCount=86 timeoutMs=30000
    

    The same thread later became readable and completed, so this was not data loss. The failure appears to be Desktop/app-server sidecar backlog or live-state wedging: retrying later may work, and a full Desktop quit/reopen makes sends work again temporarily.

  3. YoneRai12 commented on Jun 30, 2026

    @YoneRai12

    [app-server][Desktop][Windows][turn/start][thread/resume][notLoaded][Error submitting message]

    I saw a closely related Windows Desktop variant that may be a narrower race than the sidecar stall described here.

    Reproduction variant

    1. Have a stored Desktop thread that is present on disk but not currently loaded in the app-server runtime (notLoaded state).
    2. Open that long/stored thread in Codex Desktop on Windows.
    3. Submit a prompt immediately, before the thread load/resume path has visibly completed.
    4. Observed: the composer can surface Error submitting message. Fully restarting Codex Desktop clears the condition.

    This is close to this issue and #23644 because restart clears the stale/unloaded runtime state. It is related to #30704 only in the broader Windows Desktop live-state class; #30704's direct symptom is active-turn interruption from opening a local file, so I would not treat it as the primary duplicate.

    Root-cause hypothesis

    In the public app-server code, turn/start currently calls TurnRequestProcessor::load_thread, which resolves the thread id and then requires thread_manager.get_thread(thread_id) to already have a loaded runtime handle. If Desktop sends turn/start while the UI has opened a stored thread but before thread/resume finishes, the app-server path can fail as thread not found even though the rollout exists on disk.

    That error shape gives the Desktop client no structured way to distinguish:

    • a truly invalid/nonexistent thread id, from
    • a stored-but-not-yet-loaded thread that should be resumed before accepting composer submit.

    Patch proposal, if maintainers want a PR

    A small app-server contract improvement would be to return a structured retryable invalid-request error for this race, for example:

    {
      "code": -32600,
      "message": "thread not loaded or not found: <thread_id>; call thread/resume and wait for it to complete before turn/start",
      "data": {
        "thread_error_code": "thread_not_loaded",
        "retry_method": "thread/resume",
        "blocked_method": "turn/start"
      }
    }

    The Desktop client could then disable/queue composer submission until thread/resume completes, or retry after resume, instead of surfacing a generic Error submitting message.

    The same structured error is useful for nearby methods that also need a loaded thread handle, such as turn/steer, thread/inject-items, thread/settings/update, review/start, and turn/interrupt.

    Test coverage proposal

    Add an app-server integration test that:

    1. creates a fake stored rollout,
    2. starts the app-server without calling thread/resume,
    3. sends turn/start for that stored thread id,
    4. asserts the full JSON-RPC error object includes thread_error_code=thread_not_loaded, retry_method=thread/resume, and blocked_method=turn/start.

    This keeps the client-visible contract executable and avoids piecemeal field-only assertions.

    Local validation attempted

    • cargo fmt --all --check from codex-rs: passed. It emits the existing stable-rustfmt warnings about imports_granularity = Item requiring nightly.
    • git diff --check: passed, with only Windows CRLF replacement warnings.
    • Targeted test command attempted: cargo test -p codex-app-server --test all turn_start_reports_resume_retry_for_unloaded_stored_thread.
      • First local run was blocked by Windows application control while executing a dependency build script.
      • A later run was blocked by local disk space exhaustion while compiling dependencies before the test body ran.

    Per docs/contributing.md, I am posting this as issue analysis/reproduction/fix outline rather than opening an unsolicited external PR.

  4. loremcdmx commented on Jul 26, 2026

    @loremcdmx

    I hit this exact signature today and was able to trace it to a specific, reproducible cause: an orphaned codex_chronicle process holding the Chronicle lock (#19516).

    Environment: ChatGPT.app 26.721.41059, Codex Framework 150.0.7871.128, macOS 26 (Darwin 27.0.0), Apple Silicon.

    Identical renderer log to the one in the opening post:

    [electron-message-handler] mcp_request_timeout method=turn/start pendingCount=12 timeoutMs=30000
    [electron-message-handler] [Composer] submit failed errorMessage=Timeout errorName=Error followUp=local mode=local
    

    And the same queue pile-up — inFlightRequestCount pinned at 6 with app/list, skills/list, config/read and thread/list all dying with App server request expired while queued.

    The cause in my case: a codex_chronicle process (PID 1261, PPID 1) left over from an app instance four days earlier was still holding the lock, so the current app's sidecar could never start. It logged Waiting to acquire lock (owned by pid=1261) 5,074 times in one day.

    kill 1261 alone fixed it — the waiting sidecar acquired the lock 20 seconds later:

    Window submit failed expired while queued
    13:38–14:06 (before kill) 4 47
    14:10–14:19 (after kill) 0 0

    So for anyone landing here with the intermittent "Error submitting message": before anything else, check for a stale sidecar from a previous app launch —

    ps -axo pid,lstart,etime,command | grep codex_chronicle
    

    — and see whether its start time predates your current app session. Details and suggested fixes in #19516.

    This may not be the only path to the symptom described here (a sidecar can presumably stall for other reasons), but it is one concrete, verifiable one.

  5. Audacity88 commented on Aug 7, 2026

    @Audacity88

    Current-build datapoint: this also occurs under severe host CPU contention.

    Environment:

    • ChatGPT/Codex Desktop 26.730.61639, build 6234
    • Codex CLI 0.147.0-alpha.1.2
    • macOS 26.5.1 arm64

    While two unrelated development daemons were consuming roughly 195% and 141% CPU, Codex's app-server queue stopped servicing even critical requests:

    • turn/start: 30-second timeout, pendingCount=16
    • config/read: 30-second critical-priority timeout
    • thread/read and thread/list: rejected after 60 seconds queued
    • queue state included six in-flight requests and 6-11 interactive requests

    The failures occurred in both Approve for me and Full Access, including Error creating chat: App server request expired while queued. There was no stale codex_chronicle process.

    I also observed 35 idle cua_node/bin/node_repl children under the app-server during the stall. After terminating the unrelated high-CPU processes, Codex recovered and chat creation worked again.

    This suggests host CPU pressure can trigger or amplify an app-server scheduling/backpressure failure. Critical chat creation, configuration, and approval traffic should remain responsive, or background hydration should be shed earlier.

  6. genzorr commented on Aug 7, 2026

    @genzorr

    Adding a current-build macOS datapoint with a same-workspace A/B control that appears to match this issue.

    Environment

    • Codex Desktop 26.730.61639
    • macOS
    • observed 2026-08-07
    • same local project/workspace for both threads below

    This has become a frequent reliability problem over the last several days, primarily in one long-lived thread.

    Same-workspace A/B

    Affected thread turn/start response times progressed approximately as follows:

    • 26 ms at 09:36 UTC
    • 11,093 ms at 11:02
    • 38,109 ms at 11:45
    • 46,104 ms at 11:50
    • 46,580 ms at 11:58

    For the latter three, Desktop emitted a 30-second mcp_request_timeout for turn/start, but the response eventually arrived and was routed. These request records showed queueWaitMs=0.

    I then created a fresh thread in the same Desktop app / same project / same working directory. Its turn/start times were:

    • 33 ms at 11:48
    • 38 ms at 12:00
    • 139 ms at 12:14

    So the strongest local observation is:

    same project + same app + fresh thread: ~30–140 ms

    versus

    existing affected thread: ~38–47 seconds

    This argues against general backend latency, the project directory itself, or a machine-wide Desktop slowdown, and points more toward thread-local app-server/session-runtime state or request serialization.

    Compaction does not recover it

    The affected thread underwent multiple context compactions. Token accounting showed compaction-like resets around ~234k -> 0 and ~259k -> 0.

    Later, while the slow turn/start behavior was still occurring, the core log reported approximately:

    total_usage_tokens=219733
    auto_compact_scope_limit=244800
    full_context_window_limit=258400
    full_context_window_limit_reached=false
    

    So successful compaction did not restore normal message-acceptance latency.

    I also checked the public source at openai/codex@f2bee854a73666e1c3e922a853dda591b1a25fcf (2026-07-28). At that ref, app-server turn/start is serialized per thread, resolves configuration/environment/workspace-root state, then submits Op::UserInput through core. Pre-sampling compaction runs later inside admitted turn execution; it does not recreate the app-server per-thread serialization queue or live thread/session object. That makes it plausible for compaction to succeed while an independent thread-local acceptance/routing problem persists.

    At the same pinned ref, runtime_workspace_roots are resolved/deduplicated as paths; I did not find a recursive repository scan in the turn/start path. The affected request configuration had many workspace roots, but the fresh-thread result in the same project is also evidence against project-wide scanning being the primary cause.

    What would help distinguish the remaining causes

    I have preserved the affected thread and local logs and can provide sanitized excerpts if useful. The smallest useful instrumentation would distinguish time spent in:

    1. app-server per-thread request serialization before turn_start_inner runs;
    2. awaited thread/config/environment work inside turn_start_inner;
    3. core submission/admission handling;
    4. Desktop response routing after app-server completion.

    I don't think the exact internal blocker is proven yet, but the repeatable old-thread-vs-fresh-thread A/B makes this look like a thread-scoped runtime/acceptance bug class rather than ordinary model generation latency or repository size.

  7. gkb commented on Sep 27, 2026

    @gkb

    Still reproducing on a newer build — desktop 26.924.22138, codex-cli 0.158.0-alpha.2.1, macOS 27.0 (Apple Silicon).

    Same symptom: "Error submitting message — timeout", and resending ~1 min later succeeds. Some numbers that line up with the SQLite-contention theory:

    • ~/.codex/logs_2.sqlite is 2.0 GB (WAL 12 MB).
    • Running at the time: the desktop app, 4 codex CLI processes, and several computer-use helper processes.
    • Log rows per minute around one failure (local time): 12:42 → 776, 12:43 → 18, 12:44 → 7, then the next turn/start at 12:45:31, right after the error banner (12:45:14). That's the same "sidecar goes quiet, then recovers" pattern described above.
    • Log lines mentioning timeouts per day, Sep 17–26: 72, 61, 176, 361, 164, 29, 106, 20, 69, 22. It became noticeable to me around Sep 17–20.

    One confound: system load was high at the time (load average ~100, from an unrelated stuck macOS service). So heavy CPU contention may make the stall more likely, but the DB size and number of processes match the original report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appapp-serverIssues involving app server protocol or interfacesbugSomething isn't workingperformance

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions