Thread metadata can store full first user message as title, causing huge active titles

Resolved 💬 3 comments Opened May 5, 2026 by clairernovotny Closed May 5, 2026

What version of Codex are you using?

  • Codex.app: observed 26.429.30905 from the running app sample/process metadata
  • Codex CLI: codex-cli 0.128.0
  • Platform: macOS 26.4.1 build 25E253, arm64

What issue are you seeing?

Codex stores the full first user message as the thread title in ~/.codex/state_5.sqlite for some CLI/ACP/VS Code-origin sessions. This creates extremely large active thread titles and appears to make the Electron app sluggish when switching chats / rendering the thread picker.

Local evidence from state_5.sqlite:

select count(*) as rows,
       sum(length(title)) as title_chars,
       sum(length(first_user_message)) as first_msg_chars,
       max(length(title)) as max_title,
       max(length(first_user_message)) as max_first_msg
from threads
where archived=0;

Result:

134|14610549|14614033|675773|675773

The pathological subset is concentrated in RepoPrompt/ACP-like sessions:

select count(*) as rows,
       sum(case when title=first_user_message then 1 else 0 end) as exact_dupes,
       sum(length(title)) as title_chars,
       sum(length(first_user_message)) as first_msg_chars
from threads
where archived=0
  and source='vscode'
  and cwd='/'
  and title like '<codex reminder>%';

Result:

56|56|13944507|13944507

So 56 active rows have title == first_user_message, totaling ~13.9 MB of title text. 39 active rows have titles over 100 KB; the largest title is 675,773 characters.

Sample shape, sanitized:

source=vscode
cwd=/
title length=675773
first_user_message length=675773
title prefix=<codex reminder>You are operating in text only mode...

The actual rollout transcript is already stored separately via rollout_path, so the SQLite title field should not need to contain the entire first prompt.

Why this looks like a Codex metadata extraction bug

In codex-rs/state/src/extract.rs, apply_event_msg sets metadata.title directly from the stripped full user message when the title is empty:

EventMsg::UserMessage(user) => {
    if metadata.first_user_message.is_none() {
        metadata.first_user_message = user_message_preview(user);
    }
    if metadata.title.is_empty() {
        let title = strip_user_message_prefix(user.message.as_str());
        if !title.is_empty() {
            metadata.title = title.to_string();
        }
    }
}

user_message_preview also returns the full stripped message. Then codex-rs/state/src/runtime/threads.rs upserts both title and first_user_message into the threads table.

This differs from the external-agent session import path, which already has SESSION_TITLE_MAX_LEN: usize = 120 and uses summarize_for_label() to cap fallback labels.

Expected behavior

  • threads.title should be a bounded display label, not the raw first user message.
  • The fallback title path in state/src/extract.rs should use the same short-label logic or another hard cap.
  • Ideally first_user_message should either be bounded as preview data or excluded from hot UI list paths when very large.
  • Existing oversized titles should not cause the app to become sluggish when switching chats or rendering the thread list.

Actual behavior

  • Large ACP/VS Code-origin sessions can leave threads.title as a hundreds-of-KB prompt.
  • The title is duplicated into first_user_message for those rows.
  • Codex.app chat switching/thread navigation becomes sluggish; the live Electron renderer was observed with high CPU and a multi-GB physical footprint while investigating this state.

Reproduction sketch

  1. Start a Codex session through a CLI/ACP/VS Code client that sends a very large first user message and does not explicitly set a short thread name.
  2. Allow Codex to record/backfill thread metadata into ~/.codex/state_5.sqlite.
  3. Inspect threads.title for that thread.
  4. Observe that the title can be the entire first user message rather than a bounded label.

Related

Possibly related to broad app startup/thread-list performance reports such as #16158, but this issue is specifically about the unbounded thread title metadata path.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗