[BUG] Resuming sessions only works from the directory in which they were started

Status Open
Maintainer reply None cached
Activity 24 comments · opened Aug 14, 2025

Environment

  • Platform (select one):
  • [ ] Anthropic API
  • [ ] AWS Bedrock
  • [ ] Google Vertex AI
  • [X] Other: Desktop
  • Claude CLI version: 1.0.80 (Claude Code)
  • Operating System: Debian Linux
  • Terminal: VS Code terminal + bash

Bug Description

It is only possible to resume conversations from the same directory in which they are started.

Steps to Reproduce

Start a session with claude --session-id UUID
End that session and change to another directory
Try to resume the session with claude --resume UUID

Expected Behavior

Session should be resumed

Actual Behavior

Error: No conversation found with session ID: UUID

Additional Context

The problem seems to be that Claude is storing its conversations under /home/USER/.claude/projects/PROJECT_PATH/ where project path is a string built from the current working directory with the slashes removed.

View original on GitHub ↗

24 Comments

github-actions[bot] · 1 year ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/4843
  2. https://github.com/anthropics/claude-code/issues/1977
  3. https://github.com/anthropics/claude-code/issues/4926

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

allsey87 · 1 year ago

Some of the issues marked above are related but not duplicates. This issue focuses specifically on the --session-id UUID and --resume UUID pair of arguments which should be independent of the current working directory. This does not apply to --continue to which probably should continue the last conversation that took place in the current working directory.

allsey87 · 1 year ago

A simple solution to this problem which would require very few changes would be to search all of /home/USER/.claude/projects/ for a conversation when the UUID is explicitly given.

hugobiais · 11 months ago

+1

leoshatrushin · 11 months ago

+1. Our use case is in the sdk - we duplicate the root directory structure on every iteration to save history, but want to resume in the new directory

yeroc · 11 months ago

I just got bit by this one as well.

github-actions[bot] · 8 months ago

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

yeroc · 8 months ago

This is still an issue.

nullaus · 8 months ago

I can also confirm that this is still an issue. The same issue is _also_ present in the Claude Agent SDK v0.1.62.

adolago · 8 months ago

Just hit another variant of this issue. When using the resume menu (claude --resume) with A to show all projects, selecting a session from a different directory generates the wrong cd command.

What happened:

Session was created in /home/artur/Repositories (confirmed in ~/.claude/history.jsonl):
{"project":"/home/artur/Repositories","sessionId":"XXX"}

But when resuming from /home/artur/Repositories/tinygrad, the menu showed:
This conversation is from a different directory.

To resume, run:
cd /home/artur/Repositories/tinygrad && claude --resume XXX

Running that command: No conversation found with session ID: XXX

The resume menu should read the project field from the history file instead of using pwd.

Environment: Claude Code v2.0.69, Linux

jeff-hiner · 7 months ago

Just ran into this myself. Notably this is tagged "platform:linux" but it also shows up on windows, and I'd assume macos as well. Adding another use case that reinforces why this matters.

The launch directory determines Claude Code's security sandbox scope. If you start Claude from a parent directory, create a new project subdirectory during the session, and want to continue working with a tighter sandbox, you're stuck - you can't resume the session from the subdirectory.

This is particularly relevant when a session evolves from exploration/scaffolding (broad access needed) into focused development (narrower access preferred). Currently you have to choose between an overly permissive sandbox or losing your session context.

This also affects --resume <session-name> (not just UUIDs). After using /rename my-session, running claude --resume my-session from a different directory fails with "No conversations found to resume" - the name lookup is scoped to the current project directory's session store.

Manually copying the session .jsonl file and its corresponding directory from ~/.claude/projects/<old-path>/ to ~/.claude/projects/<new-path>/ does appear to work. The session loads and functions correctly from the new location. This suggests the fix could be straightforward - the session data itself isn't path-dependent, just the lookup mechanism.

andrzej-pomirski-yohana · 7 months ago

@jeff-hiner yes, this also happens on macOS. I can confirm.

GonzRon · 7 months ago

Additional reproduction case: /resume suggests the wrong directory

I encountered a variant of this bug where the /resume command actively provides an incorrect directory suggestion.

Environment:

  • Claude Code: 2.1.14
  • OS: Fedora 42 (kernel 6.17.9)
  • Shell: bash

Scenario:

  1. Launched Claude from /home/user
  2. During the session, worked on files in /opt/repos/myproject
  3. Session metadata recorded projectPath: "/opt/repos/myproject"
  4. Session file stored in ~/.claude/projects/-home-user/<session-id>.jsonl

The bug:
When running /resume, Claude suggested:
cd /opt/repos/myproject && claude --resume <session-id>

This fails because the session is stored under -home-user, not -opt-repos-myproject. The suggestion uses projectPath (where I worked) instead of the actual storage location (where I launched Claude).

Workaround: Resume from the original launch directory:
cd /home/user && claude --resume <session-id>

MarcSkovMadsen · 6 months ago

+1

I was working deeply in one repository and Claude+VS Code session, but a part of the roadmap for the feature was to move it to another repo. When done I wanted claude to change its working directory, exit and then resume from the other folder in another VS Code session.

iboxgithub · 6 months ago

still a problem today, really weird this is not prioritised, it prevents Claude CLI from actually being the single source of truth across several applications (as they all come in with their own folder structure)

dennislysenko · 5 months ago

Seems like a no-brainer to me to allow somebody to search past sessions across all projects in order to figure out which one to resume.

I don't even care which working directory they resume in. I just want the ability to find that one random session that I start every week in the wrong place and pick up from where I left off.

Especially annoying/damaging when you start a new project from a different directory - the project directory obviously didn't exist when you started it - so you have to work your way backwards and figure out which random other product folder you started from in order to be able to actually resume that.

In theory, it's a skill issue; I should write these things down or dump enough context in order to be able to pick back up without being in the same conversation. But it just seems to kind of defeat the purpose of projects partially and feels like a pretty low hanging fruit patch to make.

dennislysenko · 5 months ago

There is a workaround:

ag -l "your_search_string_here" ~/.claude/projects

will at least point you to the right project.

jakshi · 3 months ago

Filed #60851 with same root cause (macOS, but mechanism is platform-agnostic — see also #48394 on Windows and #57920 on macOS worktree removal). Letting mine auto-close as dup; migrating the proposed fix here since this thread has the most traction.

Proposed fix (minimal)

Decouple session lookup from cwd path. One small-footprint option:

  1. On session start, append the session ID to <git-root-or-cwd>/.claude/sessions (a plain newline-separated text file of UUIDs).
  2. On /resume and --continue, read that pointer file first; fall back to today's cwd-slug lookup if absent.
  3. For --resume <id>, do a global scan of ~/.claude/projects/**/<id>.jsonl so the UUID is a true global key.

Properties:

  • Pointer file is KB-sized, just UUIDs — safe to commit, sync, or .gitignore.
  • No secrets leave ~/.claude/.
  • Backward compatible: existing slug-based layout preserved as fallback.
  • Survives mv, git mv, worktree clones, symlinks.
  • Non-git dirs fall back to current behavior.

Alternative

Key the session directory by git remote get-url origin hash instead of cwd path, falling back to cwd slug for non-git dirs. Rename-proof for the common (git) case.

Why --resume <id> deserves special treatment

--resume <session-id> reads like a global lookup by a content-addressable key (the UUID), but it's actually scoped by cwd. Users reasonably expect a UUID-keyed flag to work from anywhere — the global-scan fallback in step 3 above is the smallest change that delivers that expectation.

Keesan12 · 3 months ago

Resumability keyed to the starting cwd is a trap. In MartinLoop we learned the hard way that session identity != workspace path; workspace is one dimension of context, not the primary key. If resume only works from the original directory, users lose portability and auditability the moment they move a checkout, use a different worktree, or reopen from a sibling clone.

A stronger model is stable session id -> canonical session receipt/manifest, with cwd/worktree captured as metadata and remapping warnings on resume when needed. That keeps the safety checks without making resume itself path-fragile.

tuyennn · 1 month ago

Is there any progress on this?

Adi1231234 · 1 month ago

Still hitting this, with an extra wrinkle worth flagging: it also happens when a session starts in the main repo and only switches into a worktree partway through. Once that switch happens the session gets re-indexed under the worktree's project path, so it silently drops out of /resume in the main repo with no hint that it's now stored somewhere else.

BasedGPT · 1 month ago

Ran into the same wall. The sessions aren't gone; they're filed under the project slug for whatever directory you started in, and --resume UUID only looks under the slug built from your current directory. You already spotted the mechanism in the body: ~/.claude/projects/<slug>/, where the slug is the cwd with the slashes swapped out. Start somewhere else and the resolver builds a different slug, looks there, and reports "No conversation found".

The part the toolkit can't touch is the resolver itself. Making --resume UUID search every slug for the UUID (what you proposed) is an upstream change to the CLI, and nothing on the file layer can force it. What I can help with is finding the session in the meantime, because it's sitting intact under the original slug.

I built BasedGPT/claude-code-session-recovery for exactly this kind of "which slug is my session under" problem. diagnose.py walks ~/.claude/projects/ and maps every slug against the transcript files inside it, so you can see which directory holds the UUID without guessing. Once you know the slug, cd back into the matching path and --resume UUID resolves. dennislysenko's ag -l "<string>" ~/.claude/projects one-liner further up the thread does the same job from the other direction, when you remember the content but not the path.

To confirm before relying on it, open ~/.claude/projects/ and check that a directory matching your original cwd exists with a <UUID>.jsonl inside. That file is your conversation history, untouched.

Hope this helps, if my tools are able to help you, would appreciate a ⭐ :)

dalberto · 1 month ago

There's a new built-in /cd command now, I've been using it for weeks to successfully move existing sessions to different directories.

emmaadelaide · 23 days ago

Posting this here as issue 52494 was closed. The migration was successful-ish (but mostly not as ran into this bug in various ways).

Cowork sessions orphaned after machine migration with a Windows username change — full field report, root causes, and working repair scripts

Environment

  • Claude Desktop — Cowork (beta)
  • Windows 11 Pro (packaged/Store install: Claude_pzs8sxrjxfjjc)
  • Migration between two machines, same Claude account, different Windows usernames (old: EmmaBack, new: EmmaO'Farrell — note the apostrophe, which becomes a dash in slugs)
  • ~21 Cowork sessions, several mid-project with large context

Summary of symptoms (in the order encountered)

  1. After copying local-agent-mode-sessions to the new machine, every session failed with No conversation found with session ID: <uuid> — despite files present on disk and the same account signed in. The knowledge base resolved correctly.
  2. After repairing (below), reopening the app on the old machine silently recreated the old-username slug folders on/for the account, producing twin folders per session (...EmmaBack... and ...EmmaO-Farrell...) with conversation content split between them.
  3. Final symptom: for a migrated session, any interaction spawns a brand-new conversation .jsonl in the project folder and the app's pointer moves to it — so the session's displayed history "vanishes" the moment the user types, while the old transcript remains on disk. Users will interpret this as data loss.

Root cause

Conversations are stored under a path-derived slug:

...\local_<id>\.claude\projects\C--Users-<USERNAME>-AppData-Roaming-...-outputs\<session-id>.jsonl

The slug encodes the absolute path of the session's outputs directory. On resume, the app recomputes the slug from the current path. A username/path change means the recomputed slug no longer matches the stored folder → lookup fails → app reports "No conversation found," and on interaction it creates a fresh conversation instead of continuing the old one.

Special characters are flattened: EmmaO'FarrellEmmaO-Farrell in slugs (apostrophe → dash). Repair scripts must use the dash form for folder names but the literal form for paths inside JSON.

Compounding problems

  • MAX_PATH (260 chars): slug folder names are ~190 chars, so the full paths exceed 260. Explorer cannot open the folders, and standard PowerShell cmdlets fail with path errors — making the repair look impossible without the \\?\ extended-length prefix.
  • Old machine re-stamps old slugs: while both machines are signed into the same account, reopening the app on the old machine recreates old-username slug folders, splitting content across twins and undoing repairs. The old machine must be signed out and kept closed for repairs to hold.
  • audit.jsonl vs <session-id>.jsonl: the audit log grows independently of the conversation file; the two are easily confused during recovery.

Working repair (restored 20 of 21 sessions; last one via the workaround below)

Preconditions: Cowork fully quit, OneDrive sync paused, old machine signed out and off, full backup of local-agent-mode-sessions taken first.

1) Inventory first (read-only) — do not blind-rename. Sessions can have OLD-only, NEW-only, or twin folders; twins may both contain real conversations. List every .claude\projects slug folder with file counts, then handle:

  • OLD only → rename OLD → NEW (dash form)
  • NEW only → already fine, skip
  • Twins → inspect contents; merge/choose manually — never auto-delete

2) Bulk rename + in-file path fix (\\?\ prefix throughout; note GetDirectories("\\?\...") returns already-prefixed paths — do not prefix them again, or calls fail with "syntax is incorrect"):

$sessRoot = "\\?\C:\Users\NEWUSER\AppData\Local\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\local-agent-mode-sessions"
$skip = @()  # add session folder names needing manual handling
$renamed = 0; $fixedFiles = 0
$acct = [System.IO.Directory]::GetDirectories($sessRoot) | Where-Object { $_ -notlike "*skills-plugin*" }
foreach ($a in $acct) {
  foreach ($ws in [System.IO.Directory]::GetDirectories($a)) {
    foreach ($sess in [System.IO.Directory]::GetDirectories($ws)) {
      $sname = [System.IO.Path]::GetFileName($sess)
      if ($sname -notlike "local_*" -or $skip -contains $sname) { continue }
      $proj = "$sess\.claude\projects"
      if (-not [System.IO.Directory]::Exists($proj)) { continue }
      foreach ($slug in [System.IO.Directory]::GetDirectories($proj)) {
        $nm = [System.IO.Path]::GetFileName($slug)
        if ($nm -like "*OLDSLUG*") {
          $newNm = $nm.Replace("OLDSLUG","NEWSLUG")   # e.g. EmmaBack -> EmmaO-Farrell (dash form!)
          $target = "$proj\$newNm"
          if (-not [System.IO.Directory]::Exists($target)) {
            try { [System.IO.Directory]::Move($slug, $target); $renamed++ }
            catch { "RENAME FAILED ($sname): $($_.Exception.Message)"; continue }
          } else { "SKIPPED (twin exists): $sname"; continue }
          foreach ($f in [System.IO.Directory]::GetFiles($target)) {
            try {
              $c = [System.IO.File]::ReadAllText($f)
              $n = $c.Replace("OLDSLUG","NEWSLUG")
              if ($n -ne $c) { [System.IO.File]::WriteAllText($f,$n); $fixedFiles++ }
            } catch {}
          }
        }
      }
    }
  }
}
"Folders renamed: $renamed | files content-fixed: $fixedFiles"

Notes from the field:

  • "Access is denied" on Directory.Move = a stale handle (app, Explorer window inside the folder, OneDrive, indexer). Quit everything / pause OneDrive; a reboot-then-immediately-run clears it reliably.
  • Result in our case: 19 renamed, 22 files fixed in one pass; sessions then opened with full history.

Residual bug even after correct repair — pointer moves on interaction

For one session (twin folders, multiple conversation files in one slug folder), even with files parseable, correctly named, and correctly located: the session displays no history, and typing into any migrated session creates a new empty .jsonl and switches the app to it. This spread — each migrated session interacted with lost its displayed history the same way.

Practical workaround (works): accept the new conversation, attach the old <session-id>.jsonl transcript to it, and prompt:

"This continues a previous conversation whose transcript is attached. Read it, then summarise (1) what we were doing and decided, (2) work-in-progress state, (3) the agreed next action. Then we continue."

Rehydrated sessions are clean-born on the new machine and need no further repair. This is viable but manual, per session, and loses in-app scrollback of the original thread.

Suggested fixes

  1. Key conversations by session ID, not by a path-derived slug — or detect a path change and re-key automatically. This is the root cause; everything else is fallout.
  2. Handle long paths internally (\\?\ or long-path opt-in) so slug folders don't exceed MAX_PATH and become unrepairable by users.
  3. Don't let a stale client resurrect old slugs: a machine signed into the same account can silently recreate old-path folders and split history.
  4. On lookup failure, offer recovery instead of silently starting a new thread — e.g. "A previous conversation exists for this session under a different path. Re-link it?" The silent new-thread behaviour is what makes users believe their data is gone.

Related

  • #52494 (manual project-folder rename orphans sessions — same root cause)
  • #57109 (Cowork "No conversation found" on Windows 11 — related symptom)