CLI: codex resume picker renders "No sessions yet" before initial session load completes

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

What issue are you seeing?

On Codex CLI 0.118.0, running codex resume from a repo that already has saved sessions can render an incorrect empty state on the first frame:

No sessions yet

I reproduced this in /Users/dxm/gitlab/alloy-test on macOS.

The saved sessions are not actually missing:

  • codex resume --last successfully resumes the latest session for the repo.
  • codex resume <session_id> works.
  • codex resume --all shows the sessions.
  • thread/list from the embedded app server returns the expected session rows for this repo, including when filtering by cwd=/Users/dxm/gitlab/alloy-test.

I traced this to the TUI picker logic. The picker clears rows and starts an async load, but the empty-state renderer checks:

  • all_rows.is_empty() && num_scanned_files == 0 -> render No sessions yet

before it checks whether an initial load is still pending.

So the first frame reports “no sessions” even though the session page is still loading.

Relevant code in rust-v0.118.0:

  • codex-rs/tui/src/resume_picker.rs around start_initial_load()
  • codex-rs/tui/src/resume_picker.rs around render_empty_state_line()

What steps can reproduce the bug?

  1. Use Codex CLI 0.118.0 on macOS.
  2. Ensure a repo already has saved interactive sessions.
  3. Run codex resume from that repo.
  4. Observe that the picker can initially render No sessions yet even though saved sessions exist.

In my case:

cd /Users/dxm/gitlab/alloy-test
codex resume

Related checks:

cd /Users/dxm/gitlab/alloy-test
codex resume --last
codex resume --all

To verify the data layer itself is fine, I also queried the embedded app server directly with thread/list using:

  • modelProviders = ["codeproxy"]
  • sourceKinds = ["cli", "vscode"]
  • sortKey = "updated_at"

and it returned the expected /Users/dxm/gitlab/alloy-test session row.

What is the expected behavior?

The resume picker should not render No sessions yet while the initial session page is still loading.

Expected behavior:

  • show a loading state such as Loading sessions... on the initial frame, or
  • avoid showing the empty-state message until the initial async load has completed.

Additional information

Environment:

  • Codex CLI: 0.118.0
  • OS: macOS 26.3.1 on Apple Silicon
  • Terminal: Apple Terminal

A direct thread/list check from the embedded app server returned rows quickly on the same machine:

  • initialize: about 121 ms
  • thread/list: about 230 ms

So this does not look like session loss or a backend filtering problem. It looks like a TUI state-ordering / empty-state rendering bug in the resume picker.

View original on GitHub ↗

2 Comments

github-actions[bot] contributor · 4 months ago

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

  • ##16514

Powered by Codex Action

dahuaxiya · 4 months ago

I dug into this a bit more locally and it looks narrower than “session lookup failed”.

What I confirmed on 0.118.0:

  • thread/list already returns the expected /Users/dxm/gitlab/alloy-test session row on the first page.
  • thread/list with cwd=/Users/dxm/gitlab/alloy-test also returns the expected row.
  • codex resume --last works because it bypasses the picker and directly calls thread/list with a cwd filter.
  • codex resume goes through the TUI picker and can show No sessions yet on the first frame before the async page load completes.

The likely root cause is the empty-state ordering in the picker:

  • start_initial_load() clears all_rows, resets pagination, sets loading = Pending, and then kicks off the first async page request.
  • render_empty_state_line() currently checks all_rows.is_empty() && num_scanned_files == 0 and renders No sessions yet before it checks loading.is_pending().

So the first frame can report “no sessions” even though the initial page is still loading.

A minimal fix seems to be:

  1. In the picker empty-state renderer, check the initial pending-load state before rendering No sessions yet.
  2. Show something like Loading sessions… when loading.is_pending() and the first page has not been resolved yet.
  3. Add a TUI unit test that covers the state immediately after start_initial_load() and before the first background page is ingested.

That would make the UI match the actual backend behavior without changing session lookup itself.