Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
- Start a Codex thread and set a goal with
/goal …, so the goal is active and Codex continues turns on its own. - Restart the T3 server while the goal is still active. In my case the desktop app's server restarted on its own about 45 minutes after the goal was set (
server-runtime.jsonstartedAt). - Keep using the thread. I handed off to Claude for a few runs, then back to Codex with "continue".
Observed once, over ~20 hours, in a single thread. I haven't run a clean minimal repro.
Expected behavior
Goal continuation turns are attached to a run and render in the timeline. Failing that, the existing guard in the turn/started handler (orchestration-v2.codex-goal-turn-without-run: pause the goal and send turn/interrupt) stops them. Codex work shouldn't run for hours without any trace in the UI.
Actual behavior
After the restart, no Codex run in the thread gets any projected work items. The active run shows only "Working for 1h 23m" and "Thinking". Runs #16 and #17 show "Run interrupted before provider start". Run #19 stayed running for 2 hours with exactly one turn item (the user message).
Codex was working the whole time. In ~1.5 h it made 5 commits in the repo, and the provider log has ~1,200 events (commands, reasoning, agent messages, turn/started for new goal turns) on the main native thread. Subagent native threads were projected normally. Only the main thread's items were missing.
What the code and data suggest (server bundle, Codex adapter v2). This is inference; I didn't step through it in a debugger.
item/started/item/completedcallawaitActiveTurn(payload.turnId)and return silently when no context exists, so every item of an unregistered turn is dropped.- The guard in
turn/startedrequiresrootProviderThreads.has(threadId).rootProviderThreadsis in-memory only and is populated inrunGoalCommand, i.e. only when/goalruns in the current server process. After a restart it is empty, so the guard never fires, the turn falls through torememberSubagentTurnStarted, and its items are dropped. I found nocodex-goal-turn-without-runwarning in the server logs. - When T3 later sent
turn/startfor run Track per-thread terminal running state in UI and store #19, Codex returned an existing turn id (status: "inProgress",startedAt: null) that it had started on its own hours earlier.registerRootTurnwas called withwaitForNativeStart: true, but no newturn/startedfor that id arrived.orchestration_v2_projection_provider_turnshas no rows for this provider thread after run oxc stack #1.
Workaround that worked once: quit and relaunch the app. This also stops the old codex app-server. The next Codex run rendered normally (messages, commands, browser use, tasks), and /goal wasn't needed. I haven't confirmed whether later goal continuation turns in the new server process stay visible.
Possible fixes:
- Rehydrate goal state on server start or provider-thread resume (e.g.
thread/goal/getfor root provider threads), or persistrootProviderThreads. - When
turn/startreturns an already in-progress turn, register it right away instead of waiting for aturn/startedthat never comes. - At minimum, log a warning instead of silently returning when item events arrive for an unknown turn on a root provider thread.
Related, but not the same trigger: #20232 (native goal work continues behind a failed run after /goal resume), #18833, #16942.
Impact
Major degradation or frequent failure
Version or commit
v0.1.0 (stable desktop release)
Environment
macOS (Darwin 25.2.0, arm64), T3 Code desktop app with local server; Codex provider gpt-6.1-sol, Claude Agent provider claude-opus-5-5 in the same thread via context handoff
Logs or stack traces
# provider log, main native thread, run #19 start (UTC)
16:25:41.094 outgoing thread/inject_items (context handoff)
16:25:41.112 outgoing turn/start input=[{text:"continue"}]
16:25:41.115 incoming result turn.id=<T> status=inProgress startedAt=null # <T> was first started 18 h earlier
16:25:59.567 incoming item/started userMessage "continue" turnId=<T>
... ~1,200 item/* and turn/started events on the main thread over the next 1.5 h
# state DB (copy), run #19
orchestration_v2_projection_turn_items where run_id = run #19 -> 1 row (user_message)
orchestration_v2_projection_provider_turns for this provider thread -> last row from run #1
Activity
juliusmarminge commentedon Oct 19, 2026
Note
Grok responding on behalf of Julius.
Thanks for the detailed log excerpts. I checked the diagnosis against current main, and two parts don't match it.
apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts:1904). It is filled every time T3 registers a root turn (CodexAdapterV2.ts:1931-1938,:2046), not only when/goalruns, so it doesn't stay empty after a restart.turn/startreturns a turn that hasn't started yet, the turn is registered right away and its items can attach to it (CodexAdapterV2.ts:1984-2024,:6225-6230). Only a Stop waits for the native start.Items for a turn T3 never registered are dropped without a log line (
CodexAdapterV2.ts:2058-2080,:4766-4769). That part matches, but it doesn't explain why your registered turn showed nothing.Since this happened once on 0.1.0, could you share whether it happens again on the latest nightly? If it does, the server log from around the restart and the first run after it would help most.
michal-jarczewski-deel commentedon Oct 29, 2026
Thanks Julius. I haven't confirmed another occurrence on my current desktop install (0.1.5), and I haven't run a controlled repro on the latest nightly.
Verified from the retained provider logs for the original incident (all times UTC):
Later, for run #19 on October 19, the logs show
thread/inject_itemsat 16:25:41.094,turn/startat 16:25:41.112, and its response at 16:25:41.115 returning an existing turn withstatus: "inProgress"andstartedAt: null. That turn's originalturn/startedwas at 22:04:19.660 the previous day.The earlier resume/goal/EmptyInput sequence looks consistent with the failure described in your PR #25935. Perhaps registering the root before resume will prevent the chain that led to the later invisible run, but that is still an inference.
We need to wait for #25935 to be merged and available in a build, then retest the original macOS restart → Claude → Codex “continue” sequence before confirming this issue is fixed. The existing-in-progress-turn response above is the additional case to check.
costaspanay commentedon Nov 11, 2026
Confirmed another occurrence on T3 Code
0.1.9-nightly.20261111.4501, macOS 27.0 (26A428), Codex app-server 0.167.1. This follows an automatic server-restart continuation, rather than an explicit/goal resume. It combines the invisible execution described here with theEmptyInputfailure in #20232.Observed sequence
An existing long-running Codex thread had an active goal. The local server restarted at 2026-11-11 05:15:44.547 UTC (
server-runtime.json.startedAt). T3 projected a “T3 Code restarted and resumed this turn” notification, followed by the generic “The provider could not start this turn” error.Two automatic continuation attempts failed, followed by three manual
continueattempts. Changing the selected model fromgpt-6-astratogpt-6.1-soland back did not recover visible execution. All five T3 runs (ordinals 75–79) were persisted asfailed.Despite that failed UI state, the same native Codex turn continued receiving the manual messages and executing commands and file changes. The provider event log records work after the latest displayed error, while T3's thread activity contains only the failed runs and no corresponding new work items.
Sanitized protocol evidence
Selected fields from the affected thread's provider event log; all timestamps UTC on 2026-11-11.
<N>is the same native thread throughout and<T>is the same native turn throughout. Identifiers, workspace paths, credentials, task content and unrelated payloads are omitted.A read-only inspection of
orchestration_v2_projection_run_attemptsconfirmed that the latest attempt hadstatus:"failed", the correctnativeThreadId, andproviderTurnId:null. T3's thread read returnedstatus:"failed"andactiveRunId:nulleven though the provider log showed continued native execution.Reproduction and verification limits
This is evidence from the affected live session, not a clean deterministic reproduction. The observed path was:
turn/start input=[],EmptyInput, and the generic failed-run banner.continue; repeat with a different Codex model selected.item/*events for the original turn.No provider restart, goal clear, database edits or recovery experiment was performed during diagnosis. The cause of the server restart was not established. The adapter's exact internal reason for marking the nonempty retries failed has not been established.
Expected recovery / restoration check
The automatic continuation should not leave an untracked active native turn after
EmptyInput. When a nonempty retry returns an already in-progress native turn, T3 should either attach and render it correctly or stop/reconcile it explicitly. It must not report an idle failed thread while that thread's native agent continues editing files.A useful E2E check would cover restart during an active goal, the empty-input failure, a subsequent nonempty retry, and visible command/file-change events matching the native turn. Switching models should not be required for recovery.
Related: #20232 and the still-open proposed fix #25935. #17589 is closed without being merged; it should not be treated as a shipped recovery fix.
Prepared with GPT-6.1-Sol through Codex in T3 Code, at the affected user's request. No full transcript or raw log upload is included.
test(server): wait on the interrupt request instead of wrapping notif…