codex - 💡(How to fix) Fix Thread metadata can store full first user message as title, causing huge active titles [3 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openai/codex#21154Fetched 2026-05-06 06:25:50
View on GitHub
Comments
3
Participants
2
Timeline
10
Reactions
0
Timeline (top)
labeled ×4commented ×3cross-referenced ×2closed ×1

Code Example

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;

---

134|14610549|14614033|675773|675773

---

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>%';

---

56|56|13944507|13944507

---

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

---

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();
        }
    }
}
RAW_BUFFERClick to expand / collapse

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.

extent analysis

TL;DR

The issue can be fixed by modifying the apply_event_msg function in codex-rs/state/src/extract.rs to cap the title length when setting metadata.title from the user message.

Guidance

  • Review the apply_event_msg function to ensure it correctly handles large user messages and sets a bounded title.
  • Consider adding a hard cap to the title length, similar to SESSION_TITLE_MAX_LEN used in the external-agent session import path.
  • Investigate using the summarize_for_label() function to generate a short label for the title, instead of using the full user message.
  • Verify that the changes do not introduce any regressions in thread title display or chat switching performance.

Example

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() {
            // Add a hard cap to the title length
            let max_title_len = 120;
            metadata.title = title.chars().take(max_title_len).collect();
        }
    }
}

Notes

The provided code snippet is a possible solution, but it may require further modifications to ensure correct functionality. Additionally, the performance impact of the changes should be verified to ensure that the app remains responsive.

Recommendation

Apply a workaround by modifying the apply_event_msg function to cap the title length, as shown in the example code snippet. This should prevent the app from becoming sluggish due to large thread titles.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

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.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

codex - 💡(How to fix) Fix Thread metadata can store full first user message as title, causing huge active titles [3 comments, 2 participants]