[BUG] Desktop (macOS): account switch wipes customGroupAssignments in dframe-store — custom groups survive but render empty
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Desktop app version: 1.11847.5
OS: macOS 26.2 (Apple Silicon)
Switching between two accounts (team → personal) in the Claude Desktop app wipes the chat→group assignments of custom sidebar groups. After switching back:
- "Group by: Custom groups" shows all custom group headers, but every group is empty and all sessions appear under "Ungrouped".
- "Group by: Project" still shows all sessions correctly.
The group definitions survive; only the memberships are destroyed. The loss is permanent (see "Why recovery is impossible" below).
Not a duplicate of #59640 / #32345 / #34359. Those document claude_desktop_config.json being rewritten from incomplete in-memory state (observed on Windows, trigger = preference write/quit). This report is a different storage location, a different trigger, and a selective wipe:
| | #59640 family | this report |
|---|---|---|
| Storage | claude_desktop_config.json (preferences.epitaxyPrefs.dframe-local-slice) | localStorage LevelDB, origin https://claude.ai, key dframe-store |
| Trigger | preference write / app quit | account switch |
| Wipe signature | whole groupings blob | customGroupAssignments + customGroupOrder pruned, customGroups definitions survive |
Forensics
The sidebar store is persisted as one localStorage value at:
~/Library/Application Support/Claude/Local Storage/leveldb/
key: _https://claude.ai\x00\x01dframe-store
Post-switch state extracted from LevelDB (sanitized). All 5 group definitions are intact, but the assignments map — which held dozens of entries before the account switch — is down to a single entry:
{
"state": {
"groupByByMode": {"code": "custom"},
"customGroups": [
{"id": "cg-aaaa…", "name": "Group A"},
{"id": "cg-bbbb…", "name": "Group B"},
{"id": "cg-cccc…", "name": "Group C"},
{"id": "cg-dddd…", "name": "Group D"},
{"id": "cg-eeee…", "name": "Group E"}
],
"customGroupAssignments": {
"code:local_04e6…": "cg-eeee…"
},
"customGroupOrder": {
"cg-eeee…": ["code:local_04e6…"]
}
},
"version": 0
}
There is also a companion cross-tab sync key LSS-persisted.dframe-local-slice on the same origin carrying {pinnedOrder, customGroupAssignments, customGroupOrder} — same wiped content.
Why the selective wipe pattern points at account-scoped pruning: session metadata is stored per account/org under ~/Library/Application Support/Claude/claude-code-sessions/<accountId>/<orgId>/*.json (cf. #29373), and those files carry no group field — dframe-store is the only place memberships exist, and it is global across accounts. The assignment keys reference local session ids (code:local_<uuid>). While the other account is active, those ids don't resolve to any visible session, so a cleanup/persist pass that prunes assignments for "non-existent" sessions would produce exactly the observed result: definitions kept, memberships dropped. (Hypothesis from on-disk evidence; I don't have app source access.)
This also explains why "Group by: Project" is unaffected — it's computed from the per-account session files, not from the store.
Why recovery is impossible
LevelDB compaction discards prior versions of the value within hours. By the time the user notices ("my groups are empty"), every surviving snapshot in the .ldb/.log files is post-wipe (verified by parsing all SSTables, including snappy-compressed blocks, plus IndexedDB and all partitions). Without an external backup the memberships are unrecoverable, and the user has to re-drag every chat into every group.
Steps to Reproduce
- macOS desktop app, signed into account A (personal). Create several custom groups in the Code sidebar and drag sessions into them ("Group by: Custom groups").
- Switch to account B (team org) via the in-app account switcher.
- Use the app briefly, then switch back to account A.
- Sidebar with "Group by: Custom groups": group headers are present, all groups empty, all sessions under "Ungrouped". "Group by: Project" still shows everything.
Expected Behavior
Either custom group assignments are stored per account (so each account has its own grouping, untouched by the other), or the global store must never prune assignments while a different account's session list is loaded. Group memberships should survive account switching, as the group definitions do.
Workaround / mitigation
None in-app. I now run a cron that snapshots the dframe-store value out of LevelDB so memberships can be restored by re-injecting the value into the write-ahead log while the app is closed — that works, but obviously shouldn't be necessary.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗