Custom session titles bleed across forked/resumed sessions and overwrite /rename names

Status Open
Reported on v2.1.218
Maintainer reply None cached
Activity 3 comments · opened Jul 24, 2026

Environment

  • Claude Code 2.1.218 (CLI), Windows 11 Pro 10.0.26200
  • Long-running project with many sessions, frequent /resume, occasional forks

Summary

Custom session titles set with /rename are later overwritten in the resume picker by titles belonging to other sessions. Inspecting the ~/.claude/projects/<project>/<session-id>.jsonl transcripts shows "type":"custom-title" records from unrelated tasks appended to a session's file, and the same title re-stamped many times (apparently once per resume). The picker shows the last record written, so whichever window/lineage was touched most recently silently relabels its sibling forks.

Observed evidence (from the transcript files)

One long-lived session was renamed twice by the user, then relabeled by title records the user set on different tasks:

  • Session A (122 MB transcript, 22 custom-title records):

Performance Improvements, and PRs 5549 + 5550 -> Performance Improvements, PR 5550 (both via /rename in that session) -> then six+ identical records of Analyze Nightly CDash test results (a name belonging to a different task) stamped after them. The picker now shows the wrong name.

  • Session B (a fork of session A's lineage, 18 custom-title records):

Analyze Nightly CDash test results -> Review PR for SW-18634 — the second title belongs to a completely different conversation.

  • Session C: Review PR for SW-17136 -> Review PR for SW-18634 (same cross-task overwrite pattern).

All records carry the sessionId of the file they sit in, i.e. the writer believed it was titling that session. The repetition (6/18/22 identical records) suggests the current title is automatically re-appended on every resume, so once a wrong title lands on a shared lineage it keeps propagating.

Expected

  • A name set with /rename should stick to that session and never be replaced by a title from another session or by automatic re-stamping.
  • Forked/resumed lineages should not share title state.

Impact

The resume picker becomes untrustworthy for multi-session workflows — the user could no longer find sessions by the names they had set, and stopped using resume entirely. Workaround in use: resuming by raw session ID and keeping an external ID->topic map.

Repro sketch

  1. Start a session, /rename it to NAME1.
  2. Resume/fork the same lineage in another window, /rename that one to NAME2.
  3. Resume each a few times.
  4. grep '"custom-title"' ~/.claude/projects/<proj>/<id>.jsonl — both files accumulate repeated records, and the original session's effective title becomes NAME2.

View original on GitHub ↗

3 Comments

littlemyx · 1 month ago

Independent confirmation on macOS, v2.1.220 (you're on Windows 2.1.218, so it's cross-platform), plus a version bisect and the exact trigger. This looks like the same bug as #78264 part 2.

The re-stamping you noticed ("apparently once per resume") is actually once per turn — 17 identical custom-title records in a 400-line live session file here, 53 and 243 in older ones.

The mechanism behind the bleed: when a new session id is created, the previous session's title record is written as line 1 of the new file, before any user message. Since the session then already has a title, no ai-title is ever generated for it, so the borrowed name sticks permanently and every subsequent turn re-writes it. That is also why /rename gets overwritten: whichever lineage the app holds in memory keeps stamping its own title into the file.

Version bisect over my ~/.claude/projects/**, counting sessions whose first title record precedes their first real user message:

| CLI version range | sessions | inherited a title |
|---|---|---|
| 2.1.156 → 2.1.202 (9 Jun – 8 Jul) | 21 | 0 |
| 2.1.204 → 2.1.220 (8 Jul – today) | 52 | 26 |

So it landed in 2.1.204 / 2.1.207.

One thing worth flagging because it sends you looking in the wrong place: the dominant trigger is /new, but /new writes itself into the transcript under its legacy name <command-name>/clear</command-name>. Here: 75 session files contain a /clear record and exactly 1 contains /new, while my typed-prompt history shows /clear unused since April 2026 and /new used 142 times since. Of 43 affected sessions: /new 21, background-job dispatch 15, /branch ~5, /compact 1–2.

Relaunching claude instead of using /new avoids it — of 205 sessions started by a plain launch, none inherited a name.

hendrik-hackerone · 17 days ago

Hitting this too, on a third platform and a newer build. Two data points that may narrow the cause.

Environment: Claude Code 2.1.227, macOS (darwin 25.6.0), zsh, CLI. (This issue is Windows/2.1.218; #78264 is Linux/2.1.173 — so all three platforms, still present on 2.1.227.)

1. Fork/resume is not required to trigger it

Both this issue and #78264 frame the bleed around /resume forking a lineage. My case has no fork and no resume in it at all:

  • Two sessions, same project directory, independent lineages — each begins with /clear, started a day apart (Aug 11 08:08 vs Aug 12 10:17), different first messages. Neither is a fork or resume of the other.
  • Zero ai-title records in either transcript (grep -c '"type":"ai-title"' → 0), so the ai-title-wins mechanism from #78264 isn't involved either.

Titles below are pseudonymized; timestamps, line numbers and ordering are verbatim.

Session A — 517-line transcript, only two distinct custom-title values in its entire history:

line   0   'Project planning — Q3 workstream'     ← set by me at session start
line 328   'Feature work — component X'           2026-08-13T08:27:09.032Z

No /rename was issued in Session A at 08:27 — I was mid-conversation on an unrelated topic.

Session B — same project directory:

line   0   'TICKET-102 fix cancel/recreate errors'
line   9   'Feature work — component X'             2026-08-12T10:17:48.110Z
line 311   'TICKET-126 store fee field'             2026-08-13T06:51:20.250Z
line 421   'Feature work — component X'             2026-08-13T07:57:50.879Z

Session B sets 'Feature work — component X' at 07:57:50. Session A is overwritten with that exact string 29 minutes later at 08:27:09, with no action from me in Session A.

Matches the behaviour described here: the record sits in Session A's file carrying Session A's own sessionId, and it's re-stamped on roughly every turn boundary afterwards (16 identical custom-title records), which is why the wrong title reappears after /rename corrects it.

So fork/resume looks like one path to the bug rather than a precondition — plain concurrency in a shared cwd is enough.

2. Possible cause: a single per-cwd session record

~/.claude/sessions/ contains only one record for this project despite multiple concurrent sessions in it, and it carries the bled-in name:

{
  "pid": "<pid>",
  "sessionId": "<session-a-uuid>",
  "cwd": "/Users/<user>/projects/<org>/<repo>",
  "procStart": "Tue Aug 11 08:12:55 2026",
  "version": "2.1.227",
  "kind": "interactive",
  "name": "Feature work — component X"
}

If title writes resolve the target session through a per-cwd record like this one, a rename in any session would land on whichever session owns that record — which would explain both the fork case reported here and the no-fork case above.

Happy to supply the two real session UUIDs privately if that helps reproduce.

vladysta · 11 days ago

Another writer that bypasses /rename, distinct from the ones described so far: the Remote Control bridge. On 2.1.234/2.1.235, Linux.

The reports above cover /new (recorded as /clear), background dispatch, /branch and /compact. Here the overwrite came from a source none of them names — a bridged session re-stamping the title from its cloud-side copy.

What I saw

I renamed two archived sessions from the CLI. Both renames were written and both held. Hours later, without my touching either session locally, both were back to their original — identical — name. The tail of the transcript records it plainly:

{"type":"custom-title","customTitle":"ARCHIVE 07: …"}       ← my rename
{"type":"custom-title","customTitle":"<original name>"}     ← reverted
{"type":"agent-name","agentName":"<original name>"}         ← and stamped here too
{"type":"user","isMeta":true,"message":{"content":
   "<system-reminder>The user named this session \"<original name>\"…"}}

I re-applied the rename; ~16 hours later it reverted again the same way.

Why the bridge is implicated

Two different local session files carry the same bridgeSessionId:

{"type":"bridge-session","sessionId":"0cf795a6-…","bridgeSessionId":"cse_01Lz…"}
{"type":"bridge-session","sessionId":"12166a77-…","bridgeSessionId":"cse_01Lz…"}

One cloud session id mapped onto two local sessions. And the file ends with:

{"type":"system","subtype":"bridge_status",
 "content":"/remote-control is active · Continue here, on your phone, or at https://claude.ai/code/session_…"}

Both reverts land immediately after a bridge-session record with a bumped lastSequenceNum, i.e. on bridge attach. The cloud copy keeps the old name and pushes it back down over the local one. Worth noting the session was not idle: assistant messages arrived in it from the phone/web while I considered it archived — so the bridge is not only relabelling, it is keeping "archived" sessions live.

Two details that may help locate the fix

agent-name is stamped alongside custom-title. There appear to be two title-resolution paths: the agent view (getLogDisplayTitle) starts with agentName, while the /resume picker does not consult it at all. So a rename that only writes custom-title can leave the agent view showing the stale name even when /resume is correct — the two views disagree. Any fix should update both, or the picker path should be the single source of truth.

The collision check already exists but is not on this path. The binary contains:

"The user asked to name this session "X"; another live session on this machine already holds that name, so this session is "Y"."

So /rename already refuses to create two identically-named live sessions. The bridge write does not go through that check — nor, as far as I can tell, do the compaction and /new paths described above. Routing every title write through the existing collision resolver would fix the visible symptom across all of these reports at once, independently of the separate question of why the titles are being copied.

Impact

Same as the original report: the picker stops being trustworthy. In my case one conversation ended up in three files with the same name and the same first-message timestamp, and I answered in the wrong branch more than once.

I've fallen back to a SessionStart hook that de-duplicates titles on disk. To be clear that this does not make the bug any less worth fixing: the hook relabels files, it does not stop them being created or bleeding into each other, it cannot merge a conversation that has already been split, it only runs after the damage, and it does nothing on claude.ai or mobile — which, given that the bridge is the writer here, is precisely where I need it. It buys back a readable list, not peace of mind.

Filed separately as #87884: even with the naming fixed, compaction creating a second session at all is the thing I'd like to see go away — that issue covers the session-identity layer, this one the title layer.