Codex App hides existing threads when a project is reopened via a symlinked workspace path on macOS

Open 💬 9 comments Opened Mar 22, 2026 by x3zvawq
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using (From “About Codex” dialog)?

26.318.11754 (1100)

What subscription do you have?

Plus

What platform is your computer?

macOS, Apple Silicon (M3)

What issue are you seeing?

After moving some projects to an external SSD and restoring them through symlinks, Codex App stopped showing the old threads for those projects in the sidebar/history UI.

The thread data was not actually lost. The local Codex data still existed under ~/.codex, including the thread database and session index. The issue only affected projects that had been moved to the external drive.

From local inspection, this appears to be a workspace path canonicalization mismatch:

  • the desktop app persisted workspace roots using the symlink path, such as /Users/x3zvawq/workspace/...
  • existing thread metadata stored cwd using the real path, such as /Volumes/SSD/workspace/...

Because of that mismatch, the app seems to treat them as different projects and does not show the old threads for the symlink-opened workspace, even though both paths resolve to the same location.

What steps can reproduce the bug?

  1. Have an existing project with Codex App threads/history already created.
  2. Move that project to an external SSD.
  3. Create a symlink from the old path to the new location, for example:
  • old logical path: /Users/x3zvawq/workspace/my-project
  • real path on external drive: /Volumes/SSD/workspace/my-project
  1. Open the project in Codex App using the symlinked path.
  2. Observe that older threads for that project no longer appear in the app.
  3. Inspect local state and thread metadata:
  • app state may still contain workspace roots under the symlink path
  • thread records may store cwd under the real path
  1. Rewriting the saved workspace-root paths in ~/.codex/.codex-global-state.json from the symlink path to the real path makes the missing threads show up again after restarting Codex App.

What is the expected behavior?

Codex App should treat a symlinked workspace path and its resolved real path as the same workspace when grouping, matching, or displaying project threads.

In other words, if:

  • saved workspace root = /Users/x3zvawq/workspace/my-project
  • thread cwd = /Volumes/SSD/workspace/my-project

and both resolve to the same filesystem location, the existing threads should still appear normally in the app.

Additional information

I investigated the local state and found that the thread data itself was intact:

  • ~/.codex/state_5.sqlite
  • ~/.codex/logs_1.sqlite
  • ~/.codex/session_index.jsonl

A manual workaround was:

  1. close Codex App
  2. back up ~/.codex/.codex-global-state.json
  3. rewrite saved workspace-related paths from the symlink form to the real resolved path
  4. reopen Codex App

After doing that, the missing threads reappeared.

This suggests the bug is likely in desktop-side workspace path persistence/comparison rather than data loss.

Possible fix direction:

  • canonicalize or resolve realpath for workspace roots before persisting and before comparing them against thread cwd
  • alternatively, compare both sides using a normalized/canonical filesystem path representation instead of raw path strings
  • add a regression test covering symlink path vs resolved path for the same workspace

View original on GitHub ↗

9 Comments

github-actions[bot] contributor · 4 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #15347
  • #13846

Powered by Codex Action

x3zvawq · 4 months ago
Potential duplicates detected. Please review them and close your issue if it is a duplicate. Support moving/remapping a workspace folder without losing thread history #15347 Windows app: threads disappear after restart when project is on a mapped network drive (possible //?/unc/... path normalization issue) #13846 _Powered by Codex Action_

This looks closely related to, but not identical with:

  • #13846: Windows mapped-drive / UNC-style path normalization causing threads to disappear after restart
  • #15347: enhancement request for remapping/moving a workspace without losing thread history

My case is on macOS and appears to involve a symlink path vs resolved real path mismatch:

  • workspace opened as /Users/x3zvawq/workspace/...
  • thread metadata / cwd associated with /Volumes/SSD/workspace/...

The thread data still exists locally, and rewriting the saved workspace path to the resolved real path makes the threads reappear.

So this seems closest to #13846 at the root-cause level (path normalization / canonicalization mismatch), while #15347 is a broader product feature request rather than the same bug.

x3zvawq · 4 months ago

After applying the initial workaround and restarting the app, all missing threads became visible again in the desktop UI.

However, a second issue appeared:

  • the restored threads were visible in the list at first
  • after clicking one thread, that thread would disappear from the desktop thread list again
  • the thread itself was still usable after opening it, and I could continue working in it
  • but once I switched away, I could no longer switch back to it from the desktop UI

From local inspection, this did not look like actual data loss:

  • the thread still existed in ~/.codex/state_5.sqlite
  • it was not being marked archived
  • its metadata still looked intact

So this seemed to be a second desktop-side UI/filtering issue triggered after opening a restored thread, rather than the thread actually being deleted or lost.

varoudis · 3 months ago

Will this be fixed? Why are threads disappear?

KevinAsher · 3 months ago

Same issue. It's the second time I update, recent-ish threads are kept, 2-week-ish ones are gone. Is there some type of default filtering going on by date? Or perhaps a reset per install?

acpatelmd · 2 months ago

Comment drafted by Claude (Anthropic) and posted by @acpatel after empirical test on a personal macOS workspace; technical claims verified against openai/codex source.

Root-cause confirmation across the path-divergence reports.

Comparing #15448 with #11019 / #12679 / #13846 — they reduce to the same shape: session_meta.cwd is written once at thread creation in the rollout JSONL and never updated, so any later divergence between the workspace path Codex Desktop is opened in and that recorded cwd drops the thread out of the chat-list filter. Triggers seen across the four issues: Finder folder move, symlink ↔ realpath canonicalization, Windows UNC ↔ drive-letter, and Library/CloudStorage/OneDrive-X/ABC ↔ relocated /Users/X/Y/ABC. The thread data is intact in ~/.codex/sessions/; only the listing hides it.

From ThreadResumeParams.ts: resume is by thread_id with cwd accepted as an override — so the recorded cwd isn't load-bearing for resume itself. The failure is purely in the chat-list filter, which never surfaces the thread to be resumable.

One-shot user workaround (tested on macOS 15, on a 6-week-old thread, 39MB / 13,980 records / 29 compactions — thread reappeared and resumed cleanly):

THREAD_ID="<your-thread-uuid>"
NEW_CWD="<absolute path of the workspace you now open Codex in>"
FILE=$(ls ~/.codex/sessions/*/*/*/rollout-*-${THREAD_ID}*.jsonl)

# backup as a single tar (no on-disk file accumulation)
tar -czf ~/codex-thread-${THREAD_ID:0:8}-pre-rewrite-$(date +%Y%m%d-%H%M%S).tar.gz \
  -C "$(dirname "$FILE")" "$(basename "$FILE")"

# rewrite ONLY the head record's payload.cwd; leave body transcript content untouched
python3 - "$FILE" "$NEW_CWD" <<'PY'
import json, sys
path, new_cwd = sys.argv[1], sys.argv[2]
with open(path) as f: lines = f.readlines()
head = json.loads(lines[0])
head['payload']['cwd'] = new_cwd
lines[0] = json.dumps(head, separators=(',', ':')) + '\n'
with open(path, 'w') as f: f.writelines(lines)
PY

# restart Codex Desktop with the new workspace open

Body content (function_call_output payloads etc.) intentionally left alone — those are historical tool-call transcripts, often containing the path the tool ran in at the time, and rewriting them either falsifies that record or breaks Python adjacent-string-literal source captured in past bash outputs.

Proper fix candidates (rough ascending complexity):

  1. Canonicalize cwd on both sides before the chat-list filter compares (std::fs::canonicalize or equivalent). Resolves #15448 directly.
  2. Add a "Relink workspace…" action on threads with mismatched cwd (per #12679's acceptance criteria). Recovers from arbitrary moves like #11019.
  3. Show all threads with a "moved-workspace" badge when session_meta.cwd doesn't resolve to the current workspace.
andrew-transcend · 1 month ago

I am seeing the same failure mode on macOS with Codex CLI 0.136.0.

The important invariant break is that saved project roots and thread cwd rows are not normalized the same way.

In ~/.codex/.codex-global-state.json, Codex has saved project roots such as:

<home>/Desktop/SignalBrief
<home>/Desktop/AI Trading Signals

Those paths are symlinks:

<home>/Desktop/SignalBrief -> <home>/repos/signalbrief/SignalBrief
<home>/Desktop/AI Trading Signals -> <home>/repos/personal/ai-trading-signals

But ~/.codex/state_5.sqlite stores active thread rows under a mix of the symlink path and the resolved realpath:

| Saved project root | Realpath | Active threads at saved root | Active threads at realpath |
|---|---|---:|---:|
| <home>/Desktop/SignalBrief | <home>/repos/signalbrief/SignalBrief | 0 | 26 |
| <home>/Desktop/AI Trading Signals | <home>/repos/personal/ai-trading-signals | 67 | 6 |

For SignalBrief, the project is saved under the symlink path, but all active threads are under the realpath, so the project chat list can show no chats even though the threads still exist locally and are not archived.

codex doctor --summary --no-color --ascii reports:

Codex Doctor v0.136.0 · macos-aarch64
[ok] state        databases healthy
[!!] threads      state DB rows point at missing or unusable rollout files
16 ok | 1 idle | 3 notes | 1 warn | 0 fail degraded

This looks like project identity is being compared by exact raw path string in at least one UI/thread grouping layer, while other layers resolve the path to realpath.

Expected behavior: Codex should either canonicalize saved project roots and thread cwd consistently, or preserve the user-selected symlink identity consistently. If both symlink and realpath are present, the UI should merge/warn/remap instead of making chats appear lost.

leaxoy · 19 days ago

So, is there any way—even a temporary fix—to address this issue? The current state is completely unusable.

Tschanghei · 12 days ago

I hit a closely related variant in Codex Desktop on macOS today.

Context:

  • A project was originally saved/opened under an old logical path, e.g. ~/Desktop/OldProjectName.
  • The real project folder was later renamed/moved to a new path, e.g. ~/Desktop/NewProjectName.
  • Many existing Codex threads still had cwd pointing to the old logical path.
  • The Codex project label in the UI had already been renamed to the new product/project name, but the saved project path still pointed to the old path.

Observed behavior:

  • After deleting the compatibility symlink from ~/Desktop/OldProjectName to ~/Desktop/NewProjectName, Codex Desktop showed the selected project as missing with the banner equivalent to "This project folder has been deleted or moved".
  • Many older project threads disappeared from the project view/search even though the thread data still existed.
  • Recreating the symlink immediately restored access to the project and made the older threads discoverable again.

What I verified locally:

  • list_projects still reported the project label as the new project name, but the saved project path was the old path.
  • list_threads showed many historical threads with cwd equal to the old path.
  • pwd -P from the old symlink path resolved to the new real folder, and git status/log/remote were all correct.
  • No project data or git history was actually lost.

Expected behavior:

  • Codex Desktop should either treat symlink path and resolved real path as the same workspace, or provide a first-class "rebind/migrate project path" action for saved projects and existing threads.
  • If a saved project path is missing but another saved/recent path or symlink resolves to the same repository, the app should offer a repair/rebind flow instead of making users preserve an old symlink forever.

Workaround:

  • Keep a symlink at the old saved path pointing to the renamed/moved project folder.

Why this matters:

  • Users often rename projects after an MVP/project pivot. The current path binding makes the old name effectively permanent for Codex thread continuity, unless users are willing to manually edit internal state.