Generated session names collide, dedup does not apply to them, and cross-session messages to a collided name are delivered silently to one of the sessions
Summary
With around twenty Claude Code Desktop sessions open in one project directory, auto-generated session names collide. Two sessions end up answering to the same name, SendMessage delivers to one of them without error, and the sending session is told the message was sent. There is no way to tell which session received it, and no way for a sender to detect the ambiguity.
Every documented protection against this fails in this configuration, which is what makes it worth reporting rather than working around.
Environment
- Claude Code Desktop on Windows 11, direct download build
- Desktop app 1.40609.0, session runtime 2.1.247, CLI 2.1.250
- Around twenty long-lived sessions, all in a single project directory
- All sessions report
nameSource: derivedin~/.claude/sessions/<pid>.json
Observed
Two collisions in one day on one machine. The second, still live as this is written:
<project>-dd -> "Session A" cwd: <project dir>
<project>-dd -> "Session B" cwd: <project dir>
Both entries come from ~/.claude/sessions/<pid>.json, both nameSource: derived, both in the same working directory. Earlier the same day, two different sessions shared <project>-21.
Sessions are named <project-dir>-<2 hex chars>. With one shared project directory the entire name space is 256 values, so at twenty sessions a collision is likely rather than exceptional. It is a birthday problem: roughly a 53 percent chance of at least one collision at twenty sessions, and near-certain by forty.
Why the documented mitigations do not help here
The cross-session messaging documentation describes three protections. In this configuration all three fail, and they fail together:
1. Deduplication does not apply. The docs state that when a session takes a name another live session already uses, Claude Code renames the newcomer to a variant - but they also list three exceptions, the first of which is: "It doesn't check AI-generated titles or default display names." Every session here carries a default display name, so nothing is deduplicated. The protection exists precisely for this situation and is switched off for exactly the names that need it.
2. Disambiguation by working directory shows identical rows. The docs say that unless the session is connected to Remote Control, listings show each local session's working directory "so you can tell same-named sessions apart when they run in different directories." All twenty sessions run in the same directory. The disambiguating column is identical on every row, so it disambiguates nothing. A multi-session setup on a single project is the common case for this feature, and it is the case where this mitigation cannot work.
3. The escape hatch is reportedly broken. /rename is the documented way to give a session a stable name. Five open issues report that the name does not survive resume or process exit: #26240, #47197, #25090, #23610, #26134. #26240 describes a plausible mechanism - the name is appended to the session's .jsonl and only the end of the file is scanned on resume - which would make it fail worse the longer a session runs. Long-lived sessions are exactly the ones that need stable names.
Why this matters more than a cosmetic naming bug
The failure is silent. A send to a stale name fails loudly with "No agent named X is reachable", and suggests alternatives. That is the good case: the sender learns immediately. A send to a collided name succeeds, reports success, and arrives at one of the two sessions with nothing to indicate which. The sender believes the message was delivered to the intended session. It may have been delivered to a different one.
A message you believe you sent is more dangerous than one you know you did not.
In practice a message intended for one project's session can land in an unrelated project's session, where it is acted on as a legitimate instruction from a peer.
Reproduction
- Open around twenty Desktop sessions in one project directory, none explicitly renamed.
- Inspect
~/.claude/sessions/*.jsonand joinnameagainst the session titles. - Observe two or more entries sharing a
name, all withnameSource: derived. - From another session, send to that bare name. It is delivered and reported as sent, with no indication that the name was ambiguous.
Suggested fixes, any of which would help
- Apply the existing deduplication to generated names. The variant-suffix mechanism already exists; the exception for default display names is what allows the collision.
- Refuse or warn on an ambiguous bare-name send, the way a stale name already fails - a loud failure is strictly better than a silent misdelivery. Alternatively, require the disambiguating identifier whenever more than one live session answers to a name.
- Widen the generated suffix. Two hex characters is 256 values; four would make collisions negligible at this scale.
- Fix
/renamepersistence, which would give users a working way out. Covered by the issues above.
Note on a related surface
Renaming a session in the Desktop app does set a persistent title - titleSource: user survives restarts in the app's own session store. But that title does not become the messaging name: a session renamed in the app still reports nameSource: derived and keeps its generated messaging name. If those two surfaces are intended to be connected, they are not; if they are intended to be separate, the naming documentation does not say so, since it lists renaming in the Desktop app as one of the ways to name a session.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗