CLI: picker renders before initial session load completes

Resolved 💬 4 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 ↗

4 Comments

github-actions[bot] contributor · 4 months ago

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

  • #16515

Powered by Codex Action

s1korrrr · 4 months ago

I reproduced this against current main and prepared a small fix locally on branch feat/andrzej_codex-resume-picker-initial-loading (commit b6e39b3eb6b9e92628e43622a0d1b133594d65fb).

Repro summary:

  1. Open a repo that already has saved sessions.
  2. Run codex resume.
  3. On the first frame, the picker can render No sessions yet even though the initial thread-list request is already in flight and sessions exist.

Root cause:
codex-rs/tui/src/resume_picker.rs checked all_rows.is_empty() && num_scanned_files == 0 before checking whether pagination.loading was already pending. So the empty-state renderer treated "initial page request in progress" as "no sessions exist yet".

Approaches compared:

  • A) add a new initial_load_complete flag and branch the copy off that.
  • B) keep the existing state model and make render_empty_state_line(...) prefer a loading message while the initial page load is pending.

I chose B because the pending/idle state is already explicit in PaginationState, so adding another flag would just duplicate state for a one-line renderer decision.

Fix summary:

  • when pagination.loading is pending and the picker still has zero rows / zero scanned files, render Loading sessions…
  • keep Loading older sessions… for later pagination loads
  • keep No sessions yet once the initial load actually completes with no rows
  • add two regression tests covering both the pending-initial-load state and the completed-empty state

Validation from this run:

  • passed: CARGO_INCREMENTAL=0 RUSTFLAGS='-C debuginfo=0' cargo test -p codex-tui --lib render_empty_state_line_ -- --nocapture
  • passed: cargo fmt --check -p codex-tui
  • passed: git diff --check

Local environment note:

  • the host volume was nearly full during the first test attempt, so I had to rerun the targeted test after clearing this worktree’s generated target/ directory and using a lower-footprint Rust build (CARGO_INCREMENTAL=0, -C debuginfo=0). The final targeted test run above passed.

Sandbox limitation for publication:

  • this environment blocks raw git push (Could not resolve host: github.com), so I could not publish the fork branch URL directly from this run. If this direction looks right and you want an invited PR, I can push/open it quickly from the committed branch above once branch publication is available.
dahuaxiya · 4 months ago

Thanks, this matches what I saw locally.

A couple of points from my repro that may help narrow the scope:

  • thread/list returns the expected session row on the first page, both with and without the cwd filter.
  • codex resume --last works because it bypasses the picker and directly uses the filtered thread lookup.
  • The incorrect behavior is specifically the first frame of codex resume via the TUI picker.

So I agree this looks like an initial-load empty-state ordering bug in the picker, not a session lookup / filtering failure. Rendering Loading sessions... while pagination.loading is pending, and only showing No sessions yet after the first page has actually completed empty, sounds like the right fix.

Also, the related issue I opened as #16515 was closed as a duplicate of this one, so this is the main thread to track. If a PR goes up, I can test it on the same macOS setup where I reproduced the issue.

etraut-openai contributor · 4 months ago

Thanks for the bug report. This will be fixed in the next release.