Skip to content

Thread rename updates session_index but leaves SQLite thread title stale #16405

Closed

Description

@iqdoctor

Summary

Renaming a thread updates session_index.jsonl, but it does not update threads.title in state_*.sqlite for the same thread_id.

That leaves a persistent split-brain state between the append-only session index and the SQLite metadata store.

Newer resume/list code paths can paper over this by hydrating thread.name from session_index, but the underlying drift still remains and can break older resume flows, title-based search, or any surface that relies on SQLite title as the source of truth.

Concrete drift observed

For a real saved thread:

  • session_index.jsonl contained "Provision server VM"
  • threads.title in SQLite still contained "server vm"
  • the same thread id was 019c4b73-a91e-7640-9ef6-b1bf18951bb6

User-facing symptom

On affected CLI paths / older builds, codex resume 'Provision server VM' can fail with:

ERROR: No saved session found with ID Provision server VM. Run `codex resume` without an ID to choose from existing sessions.

while the same session is still resumable from the picker.

Even on newer builds where picker/list behavior is corrected by name hydration, the persisted metadata remains inconsistent.

Expected behavior

A thread rename should keep both persistence layers in sync:

  • append the new name to session_index.jsonl
  • update threads.title in SQLite for the same thread id

Why this matters

session_index is append-only and currently acts as the latest rename source, but SQLite still powers thread metadata, sorting, and some lookup/search paths. If the two stores diverge, name-based behavior becomes version-dependent and path-dependent.

Proposed fix

When append_thread_name(...) succeeds, perform a best-effort SQLite title sync for the same thread_id.

That keeps existing semantics (session_index remains append-only) while eliminating stale threads.title rows.

Activity

  1. added
    bugSomething isn't working
    CLIIssues related to the Codex CLI
    on Apr 1, 2026
  2. added
    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal display
    and removed
    CLIIssues related to the Codex CLI
    on Apr 2, 2026
  3. etraut-openai commented on Apr 2, 2026

    @etraut-openai
    Contributor

    Can you provide repro steps? You're describing internal details, but I'd like to understand the user-visible behaviors and the steps needed to repro the problem.

  4. NightGlowww commented on May 22, 2026

    @NightGlowww

    I can reproduce this on Codex Desktop for macOS, and it also has a visible sidebar/user-facing impact when the first prompt is long.

    Environment:

    • Codex Desktop: 26.519.31651, bundle version 3017
    • bundled / CLI version: codex-cli 0.133.0
    • macOS: 26.5 build 25F71, x86_64

    User-visible symptom:

    • A thread that starts with a long absolute file path / long task prompt can continue to show that long first prompt as the chat title in the Desktop Projects sidebar, even after a concise generated/renamed title exists elsewhere.
    • This makes the Projects list hard to scan because real work often starts with paths like /Users/<user>/Desktop/.../some-document.docx.

    Concrete local drift observed after restart:

    Thread A
    state_5.sqlite threads.title:
      long first prompt beginning with an absolute file path and document-editing instructions
    session_index.jsonl:
      older entry: long absolute path title
      later entry: "Course material revision"
    
    Thread B
    state_5.sqlite threads.title:
      long first prompt beginning with an unzip/package path and task details
    session_index.jsonl latest thread_name:
      "Homepage design and VIP features"
    
    Thread C
    state_5.sqlite threads.title:
      first prompt about adding an email module
    session_index.jsonl latest thread_name:
      "Email module development"
    

    I also observed a successful Desktop app-server rename request in the app log:

    method=thread/name/set ... conversationId=<thread-id> ... errorCode=null
    

    So the app/server path for rename is being exercised, but the SQLite threads.title rows remain stale while session_index.jsonl carries the later concise names. In one case, session_index.jsonl also has multiple entries for the same thread id, with the later entry being the desired short name.

    Repro steps from the Desktop side:

    1. Open Codex Desktop on macOS.
    2. Start or resume a local thread whose first user message begins with a long absolute path and detailed task text.
    3. Let the app generate or set a concise thread name later.
    4. Restart Codex Desktop.
    5. Compare:
      • ~/.codex/session_index.jsonl latest thread_name for that id
      • ~/.codex/state_5.sqlite threads.title for the same id
      • the title shown in Desktop Projects/sidebar surfaces

    Expected:

    • Rename/title generation should keep session_index.jsonl and state_5.sqlite.threads.title consistent.
    • Desktop sidebar/list surfaces should prefer the latest explicit/generated thread name, not the stale first prompt or path.

    This is especially noticeable on Desktop because long path-derived titles occupy the whole sidebar row and make project history difficult to navigate.

  5. iqdoctor commented on Jun 9, 2026

    @iqdoctor
    Author

    Yes — here is a repro-oriented version focused on the user-visible behavior rather than the internal diagnosis.

    User-visible repro shape

    The easiest way to see the problem is to start from a thread whose first/title text is short or stale, then let a later explicit/generated rename give it a different, more useful name.

    Steps

    1. Start Codex and create a new thread with an initial prompt that will produce an initial title, for example:

      server vm
      
    2. Let the thread be saved normally.

    3. Rename the same thread to a different title, for example:

      Provision server VM
      

      This can be through the normal rename/title-generation path that writes the new thread name into the session index.

    4. Exit/restart Codex so future resume/list/search paths read persisted metadata rather than only live in-memory state.

    5. Try to resume/search by the new visible title:

      codex resume 'Provision server VM'
    6. Compare the persisted metadata for the same thread id:

      rg '019c4b73-a91e-7640-9ef6-b1bf18951bb6|Provision server VM|server vm' ~/.codex/session_index.jsonl
      
      sqlite3 ~/.codex/state_5.sqlite \
        "select id, title, first_user_message from threads where id = '019c4b73-a91e-7640-9ef6-b1bf18951bb6';"

      Replace the id with the new thread id if reproducing from scratch.

    Actual behavior observed

    For the concrete thread I reported:

    • thread id: 019c4b73-a91e-7640-9ef6-b1bf18951bb6
    • latest session_index.jsonl name: Provision server VM
    • SQLite threads.title: server vm

    On affected CLI paths / older builds, this can make the new visible title fail as a direct resume key:

    ERROR: No saved session found with ID Provision server VM. Run `codex resume` without an ID to choose from existing sessions.
    

    while the same session can still be found from picker-style flows that hydrate or merge names differently.

    Expected behavior

    After a thread rename, the same thread id should have the same effective title in both persistence layers:

    • append-only session_index.jsonl records the new name, and
    • SQLite threads.title is updated/best-effort synced to the same new name.

    That way title-based resume/search/list behavior does not depend on which persistence layer a given surface uses.

    Why this is user-visible

    The visible symptom is not the database mismatch itself; it is that the user sees or expects the renamed title, but title-based lookup/search can still behave as if the old title is authoritative. On Desktop/sidebar surfaces this also shows up as stale or long first-prompt titles continuing to occupy the row even after a concise generated/renamed title exists elsewhere.

  6. iqdoctor commented on Jun 9, 2026

    @iqdoctor
    Author

    Blitz $code-review update on current main

    Checked against current openai/codex main:

    • Commit reviewed: 89ac3ec27cae0000da14fbe4160a79ed465843fb (89ac3ec27cae)
    • Scope: rename/thread-name/session_index/SQLite title paths only
    • Diff state: clean local checkout

    Short version: this looks partially fixed, but not fully closed.

    What appears fixed now:

    • The ordinary future rename path now writes both stores:
      • codex-rs/thread-store/src/local/update_thread_metadata.rs:502-516
      • it calls state_db.update_thread_title(thread_id, &name) before append_thread_name(...).

    Remaining issues found in the blitz review:

    1. [MEDIUM] Existing stale SQLite titles can still mask newer session_index names
      codex-rs/thread-store/src/local/read_thread.rs:304
      stored_thread_from_sqlite_metadata() trusts any distinct SQLite threads.title and only consults session_index when the SQLite title is missing/non-distinct.
      Related paths:

      • codex-rs/thread-store/src/local/list_threads.rs:83
      • codex-rs/thread-store/src/local/search_threads.rs:198
      • codex-rs/tui/src/lib.rs:697

      So a pre-existing split-brain row such as SQLite title server vm + latest session_index name Provision server VM can still surface the old SQLite title on read/list/search-style paths unless the stale row is repaired or latest session_index is preferred.

    2. [MEDIUM] State DB reconcile preserves stale explicit SQLite titles
      codex-rs/rollout/src/state_db.rs:515
      Reconcile calls metadata.prefer_existing_explicit_title(&existing_metadata), so an existing stale-but-distinct SQLite title is preserved rather than repaired from the latest session_index name.

    3. [MEDIUM] Derived title patches can still overwrite an explicit name in SQLite
      codex-rs/thread-store/src/local/update_thread_metadata.rs:245
      ThreadMetadataPatch::title is documented as a best-effort title derived from history, but it is applied unconditionally:

      if let Some(title) = patch.title {
          metadata.title = title;
      }

      That can recreate the split-brain state: SQLite gets a later derived title while session_index still has the explicit user-facing name. The current test metadata_patch_applies_title_over_existing_name appears to encode this behavior.

    Suggested minimal fix shape:

    • Preserve an existing explicit/user-set name when applying derived patch.title unless patch.name is also present.
    • During read/list/search/reconcile, compare the latest session_index name for the thread and either prefer it or backfill threads.title when it differs from stale SQLite.
    • Add regression coverage for: SQLite title = old, latest session_index name = new, then read/list/search/resume surfaces the new name and does not let the stale SQLite title win.

    Net: the original future-rename write path seems fixed, but legacy drift/backfill and derived-title overwrite cases still make this issue relevant.

  7. solankydev commented on Jul 17, 2026

    @solankydev

    Additional reproduction: Windows Desktop + WSL with a CODEX_HOME transition

    I can reproduce the user-visible title divergence on Codex Desktop for Windows when the selected agent is WSL and the Desktop WSL app-server's CODEX_HOME changes.

    Environment:

    • Codex Desktop: 26.715.2305.0
    • Bundled WSL runtime recorded by the task: 0.145.0-alpha.18
    • Runtime: WSL2
    • Original CODEX_HOME: Windows-mounted directory
    • Current CODEX_HOME: WSL-native directory
    • SQLite home remains WSL-native/shared

    Sanitized observations for one task ID:

    1. The task was created by the WSL agent while CODEX_HOME pointed to the Windows-mounted home.
    2. The original home's session_index.jsonl has two entries for the same task ID:
      • the initial first-prompt-derived title
      • a later concise generated/renamed title
    3. After changing the WSL app-server to the WSL-native CODEX_HOME and restarting Desktop, the new home's session_index.jsonl has no entry for that task ID.
    4. Desktop/shared SQLite can still resolve and continue the same task ID.
    5. A direct thread read on the current WSL host returns no explicit title and falls back to the initial-message preview.
    6. The Windows-side metadata surface continues to show the later concise title.

    Result: the same task ID appears with two different titles depending on which persistence surface/home is used:

    Windows-side session index: latest concise renamed title
    Current WSL/shared-state read: initial-message preview fallback
    

    This confirms the issue remains user-visible in the current build. The ordinary future rename path may now update both stores when they share one home, but an existing task discovered across a CODEX_HOME transition still does not hydrate or reconcile its latest explicit name from the rollout's owning home.

    Expected behavior:

    • One task ID should expose one effective latest title across Desktop/WSL surfaces.
    • When cross-home task discovery is supported, title lookup should either:
      • read the latest explicit name from the rollout's owning Codex home,
      • migrate/reconcile that name into shared SQLite/current state, or
      • preserve an owning-home reference in task metadata.

    This is adjacent to #33815, where the same cross-home discovery works for reading but archive routing fails. No usernames, task IDs, project paths, or transcript content are included here.

  8. rshumilov commented on Aug 21, 2026

    @rshumilov

    Still reproducible on macOS Desktop 26.818.31338 (build 6892).

    I manually renamed existing local tasks. The sidebar showed the new names immediately, but the @ mention picker did not find them by the new titles. It worked only after the task catalog refreshed; no subsequent rename was made.

    This means the stale-title/search path is still user-visible in a current desktop build. For projects with many renamed tasks, @ references are unreliable until the cache or catalog happens to refresh.

  9. etraut-openai commented on Oct 12, 2026

    @etraut-openai
    Contributor

    (response from codex)

    Closing for the CLI rename path: thread/name/set now updates both the SQLite title and the legacy index (#21260), included in CLI 0.162.1. If the Desktop sidebar still differs from its engine’s stored name, please file a current Desktop-specific report so we can trace that path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal displaybugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions