codex delete can unlink rollout, return failure, and leave a stale thread row

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

What version of Codex CLI is running?

codex-cli 0.144.4

What subscription do you have?

ChatGPT Pro x20.

Which model were you using?

Not relevant; this occurs in the local codex delete command before any model call.

What platform is your computer?

macOS 26.5.2 (25F84), arm64.

What terminal emulator and version are you using (if applicable)?

Codex Desktop integrated shell; Codex Desktop and local app-server processes were running against the default CODEX_HOME.

Codex doctor report

Before deletion, the redacted codex doctor --json state checks were healthy:

  • SQLite state integrity: OK
  • active rollout files/rows: 2,286 / 2,286
  • archived rollout files/rows: 877 / 877
  • mismatches: 0
  • missing rollout files: 0
  • stale rows: 0
  • rollout scan errors: 0

What issue are you seeing?

codex delete --force <UUID> can unlink the rollout file, then return an error and leave the corresponding row in state_5.sqlite.threads.

Observed CLI result:

Error: failed to delete session

The command exited with status 1. The rollout file was nevertheless gone. Opening the still-visible task from Codex Desktop then failed with:

Failed to resume chat
failed to resolve rollout path `~/.codex/sessions/.../rollout-....jsonl`: file does not exist

The stale threads row still contained the missing rollout_path, with archived=0 and is_pinned=0.

What steps can reproduce the bug?

  1. Start with a valid saved session whose rollout file and state_5.sqlite.threads row are in parity. In this case the rollout was 9,852,059,554 bytes.
  2. Keep Codex Desktop/app-server running against the same default CODEX_HOME.
  3. Run codex delete --force <UUID>.
  4. Observe exit status 1 and Error: failed to delete session.
  5. Verify that the rollout file has been removed but the matching threads row remains.
  6. Open the task from Codex Desktop and observe failed to resolve rollout path ... file does not exist.

The session UUID, task title, local username, repository path, and rollout contents are intentionally omitted for privacy.

What is the expected behavior?

Deletion should be atomic from the user's perspective:

  • on success, remove both the rollout representation and all corresponding thread metadata, emit the deletion notification, and exit 0; or
  • on failure, leave a recoverable session or complete/repair the metadata deletion automatically.

The CLI should not report a generic failure after irreversibly deleting the transcript while leaving an unopenable task in the catalog.

Additional information

This was encountered while cleaning up the unbounded session-storage growth tracked in #34337. The local store had reached 43,720,251,753 bytes across 2,286 active rollouts; the largest rollout was 9.18 GiB.

The stale row had no thread_dynamic_tools records and no parent/child thread_spawn_edges. After backing up the database and removing that one stale row manually, PRAGMA integrity_check returned ok and PRAGMA foreign_key_check returned no violations.

View original on GitHub ↗

3 Comments

github-actions[bot] contributor · 6 days ago

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

  • #39567

Powered by Codex Action

hacksurvivor · 6 days ago

Follow-up from the same cleanup: this reproduced on all five additional selected sessions, including one session that was first archived through the Desktop API. In every case, codex delete --force unlinked the rollout, printed Error: failed to delete session, exited 1, and left the threads row pointing to the missing path.

The five rollout sizes were 4,815,422,398; 1,537,173,934; 1,199,836,982; 1,173,158,447; and 1,111,769,635 bytes. None was pinned or active at deletion time. One 4.48 GiB rollout initially had an open Desktop writer; I navigated away, archived it successfully, waited for all readers to close, and only then deleted it. The failure mode was unchanged for the archived path.

After narrowly removing the stale metadata rows from a backed-up database, PRAGMA integrity_check returned ok, foreign_key_check returned no violations, and codex doctor reported that rollout files and the state DB inventory agree. This makes the non-atomic behavior repeatable rather than a one-off filesystem race.

pomazanbohdan · 5 days ago

Related storage-safety evidence from a Windows cleanup workflow: destructive deletion was avoided because rollout unlink and metadata deletion are not atomic. The cleaner now backs up SQLite and rollouts, performs scoped changes only after process absence, and verifies path/foreign-key/projection parity. This is adjacent to, but distinct from, the agent lifecycle cluster (#38805 and #31433).