[CLI][TUI] Session resume can fail with 'already has an active writer' after approval-mode use or session switching
What issue are you seeing?
Resuming an existing Codex CLI/TUI session can fail with an already has an active writer error, even when I expect the session to be available for continuation.
I have observed this after previously using --not-so-yolo / --approve-for-me, as well as after switching between sessions in the TUI. I am not claiming those modes are necessarily the root cause, only that they are contexts in which the failure has occurred.
The error looks like:
Error: Failed to resume session from .../rollout-...jsonl:
thread/resume failed during TUI bootstrap:
thread/resume failed: thread <THREAD_ID> already has an active writer (code -32600)
This is not Windows-specific. I have reproduced the same resume failure on both Windows and a Linux server.
The session itself still exists, but Codex refuses to resume it because the thread is considered to have an active writer.
What steps can reproduce the bug?
The exact trigger is not fully isolated yet, but I have seen it in these flows:
- Start and use an interactive Codex CLI/TUI session.
- Use
--not-so-yolo/--approve-for-me, or switch between sessions from the TUI. - Later attempt to resume the previous session with
codex resumeor through the TUI. - Codex fails during TUI bootstrap with
thread <THREAD_ID> already has an active writer (code -32600).
What is the expected behavior?
If no other client is actively writing to the thread, Codex should allow the existing session to be resumed normally.
If another writer really is active, Codex should identify the owning process/session clearly enough for the user to understand what is holding the thread and recover safely.
Additional information
The same failure has occurred across more than one environment, so it does not appear to be specific to Windows path handling or the Windows /resume picker.
9 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
The
already has an active writer (code -32600)on resume means the thread's writer lease/lock outlived the process that held it. Either the previous session didn't release the lock on exit (crash, force-kill, or an approval-mode/session-switch path that abandons the writer without cleanup), or the lock file/fd is stale but still present, so the new resume is refused even though nothing is actually writing.The way to tell which case you're in is to inspect the lock itself: who owns it, whether that process is still alive, and whether the lock's mtime is advancing. A stale lock from a dead process is safe to reason about; a live lock from a process you didn't expect is a different problem (a background writer you didn't know about).
Full disclosure: I maintain codex-rescue (https://github.com/shleder/codex-rescue).
codex-rescue writer --latestinspects active writer locks and process ownership read-only, so you can confirm whether your "active writer" is a real live process or a stale lease before you decide to clear it. It won't force-release the lock (that's a mutation), but it tells you definitively whether the resume is blocked by a ghost writer, which is the common case after approval-mode use or TUI session switching.{"detail":"Bad Request"} Error
For the active-writer resume failure, please run the check only after the Codex writer is stopped; Vetto will preserve evidence but will not override writer ownership.
Thanks for the detailed report. This is a good candidate for a bounded recovery check. Vetto 0.2.0-alpha.2 is available from npm and adds a read-only, copy-only Codex rescue adapter. It does not resume Codex, edit rollout files, or write vendor SQLite. On a disposable copy, try:
npm install --global @shleddy/vetto@next;vetto rescue --adapter codex --root <CODEX_HOME> --json scan; then use the exact returned key withdiagnoseandsnapshot ... --output ./vetto-recovery/session.jsonl. Please report OS, Codex/Vetto versions, sanitized JSON, and source SHA-256 before/after; never upload raw transcripts, auth/config, prompts, or tokens. An explicit unavailable/unsupported result is useful too.I can reproduce this consistently on Linux with Codex CLI 0.149.1 using the following sequence:
Start Codex normally.
Trigger a command that requires manual approval.
Press Ctrl+C while the approval prompt is open.
Restart with codex --approve-for-me.
Resume the interrupted session.
Resume fails with:
thread/resume failed during TUI bootstrap:
thread/resume failed: thread THREAD_ID already has an active writer
(code -32600)
Restarting normally without --approve-for-me allows the same session to resume successfully.
Additional Linux reproduction on Codex CLI 0.149.1 (2026-08-25 UTC).
I hit the same failure while trying to resume a saved TUI session:
The rollout JSONL is intact and ends with a normal
task_completerecord. The matching lock file is present at~/.codex/thread-writer-locks/<THREAD_ID>.lock. Read-only inspection showed that a still-running Codex CLI process held the lock and its write descriptor, so this instance is an active-writer lifecycle/handoff case rather than an unowned lock file. The owning process was an older TUI left running while a new TUI attempted the resume.Expected behavior: show the owning client/process, or provide a safe attach, handoff, or read-only recovery path. A duplicate lock-file deletion workaround would risk two writers.
Same writer-lock family for me across CLI/TUI switches. Worth noting for affected users: the lock lives in derived state, not in the rollout -
vetto rescue scanconfirms the underlying session files are still present and sized normally, which takes 'did I lose the transcript?' off the table while the ownership bug is open.I reproduced the exact TUI-bootstrap error on Windows during a cross-surface resume after the Desktop app update.
Environment:
26.825.3734.0(Arm64)codex-cli 0.150.128000, ARM640.142.5The failure is:
A read-only sanitized inspection found the rollout present and parseable: one
session_meta, 595turn_contextrecords, 88,715 JSONL records, and zero invalid JSON lines. I did not modify the database or rollout.A writer may still be live in the other surface. The user-visible problem is that the TUI reports only an opaque conflict. It does not identify the owning process or surface, offer observer mode, or provide a safe handoff action.
I uploaded the affected thread ID and diagnostics privately through
/feedback.Uploaded thread:
01a0470d-0700-71b0-8afb-875b432c5088Regarding the
thread <THREAD_ID> already has an active writer (code -32600)bootstrap failure:This error occurs when the Codex app-server leaves an unreleased advisory file lock or stale writer record in the local session state database (
~/.codex/state_*.vscdb/ SQLite WAL) following an abrupt TUI exit, approval modal switch, or background subagent fork. Because the runtime treats un-checkpointed WAL lock flags as live active writers, subsequentthread/resumerequests fail fail-closed.To diagnose and safely clear stale lock states without losing conversation context or wiping
~/.codex:You can use the open-source Vetto Codex adapter to inspect and repair locked session trees:
What the adapter does:
codex resume.