Repository navigation
Description
Summary
After migrating from OpenCode V1 (1.18.x) to V2 (2.0.26), all sessions that belonged to the V1 global project become invisible in the session list when OpenCode is started in the same working directory. The session list defaults to a cwd scope that filters by project + subpath, and the V1→V2 migration creates a new project for each non-git directory, so the pre-upgrade sessions (still attached to global) no longer match. The data is intact and is returned when filtering by directory instead of project.
Environment
- opencode version:
opencode v2.0.26 - OS: Windows 11 Pro, 10.0.26300 (win32 x64)
- Terminal: Windows Terminal (
WT_SESSIONset),TERM=xterm-256color - Shell:
C:\WINDOWS\system32\cmd.exe - Install/channel:
latest, bun global install (@opencode/cli@2.0.26) - Active plugins: two failing local plugins under
~/.config/opencode/plugins/(git-ai.ts,utf8-encoding.ts) — unrelated V1-style plugin shape, reported separately
Reproduction
- Use OpenCode V1 (1.18.x) with a non-git working directory, e.g. the user home
C:\Users\ivony. Create a number of sessions. Confirm they are stored under projectglobal. - Upgrade to V2 (2.0.26) and start OpenCode in the same directory.
- Open the session list (
/sessions, orCtrl+XthenL). Only the sessions created after the upgrade are listed. Sessions from step 1 are missing. - Run
opencode api get "/api/session?directory=C%3A%5CUsers%5Civony&limit=500&parentID=null"— all the missing sessions are returned.
Expected Behavior
The V1→V2 migration should keep pre-upgrade sessions associated with the same effective location, so they still appear in the default session list of the directory they were created in. Or, at minimum, the default list scope should not hide them without any indication.
Actual Behavior
Sessions are silently filtered out of the default list.
State in ~/.local/share/opencode/opencode.db for directory = 'C:/Users/ivony':
| session version | project_id | count |
|---|---|---|
| 1.18.x (pre-upgrade) | global |
244 |
| 2.0.26 (post-upgrade) | 3f432266b9eb53b3940d9e5a6122021303b35fe4 |
3 |
The project table gained a new row at upgrade time for the home directory:
id = 3f432266b9eb53b3940d9e5a6122021303b35fe4
worktree= C:/Users/ivony
vcs = (null)
time_created = 1791767834380 # upgrade time
while the pre-upgrade sessions still point at the legacy global project (worktree = '/').
API evidence (same running service, same directory):
$ opencode api get "/api/session?project=3f432266b9eb53b3940d9e5a6122021303b35fe4&limit=50&order=desc&parentID=null"
data.length = 3 # only post-upgrade sessions
$ opencode api get "/api/session?directory=C%3A%5CUsers%5Civony&limit=500&parentID=null"
data.length = 247 # all sessions, including the 244 legacy ones
Relevant client logic found in the shipped binary: the session-list dialog initializes allProjects = (tabs.scope !== "cwd"), and the default tabs.scope is "cwd", so the query becomes { project: <location project id>, subpath: <current dir relative to project.directory> }. It falls back to a directory-based query only when the resolved project is global. Search terms are applied on top of that same scope, so searching does not reveal the missing sessions either.
Also note kv table marker migration.v1-v2 = {"phase":"completed"} confirms the migration ran.
Additional Context
- The sessions are not lost. Verified by reading the DB directly and by the
directory-filtered API call above; each missing session can be opened by id. - Workaround: press
Ctrl+Ain the session list to toggle "Show all project sessions", or set"tabs": { "scope": "global" }in~/.config/opencode/cli.json. Both make the legacy sessions visible. - A proper per-session fix exists via the API:
POST /api/session/{sessionID}/movewith{"directory":"C:\\Users\\ivony"}re-associates one legacy session with the new home project and clears its subpath, after which it appears in the defaultcwd-scoped list. I used this to migrate 244 sessions one by one; it works, but there is no bulk/migration path, so an affected user with a large history must script it. - Related:
opencode api get "/api/location?directory=..."ignores the query parameter and resolves the location from the process cwd, which makes it awkward to verify location resolution for another directory from the CLI. - Frequency: reproducible consistently for every non-git directory used with V1 that has sessions (the home directory is the main one here; the same applies to WSL UNC paths such as
//wsl.localhost/Ubuntu/home/ivony).
Activity
opencode-agent commentedon Oct 12, 2026
Thanks for the very thorough write-up, including the DB evidence and the
POST /api/session/{id}/moveworkaround. I think this is a duplicate of #49827: V1 sessions from non-git directories stay attached to theglobalproject after the V1→V2 migration, while V2 creates a separate project for that directory. The defaultcwd-scoped session list then hides them, even though they're still in the database.Possible duplicates and closely related issues, ordered by likelihood:
globalsessions from non-git dirs hidden after upgrading); others confirm it there on later versionsglobalsessions to the project of their directory during migrationUntil a fix lands, the workarounds you found still apply: press
Ctrl+Ain the session list, set"tabs": { "scope": "global" }, or move sessions withPOST /api/session/{id}/move. If you have more details, such as the WSL UNC path case, adding them to #49827 would help.The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different.
Ivony commentedon Oct 12, 2026
Follow-up after digging into the 2.0.26 bundle — the root cause is broader than the one-shot V1→V2 migration, and there are two independent triggers. Confirmed from the shipped code:
So a session is listed only when
session.project_id === resolve(directory).idandsession.path === relative(project.directory, directory).1. Migration rewrites
project_idbut notpathFor directories that already had a project when the migration ran (e.g. a git repo that got adopted),
session_v2.project_idwas updated to the new project whilesession_v2.pathkept the old V1 value, which was relative to the oldglobalproject (/). The sessions then match the project but not the subpath, so they are filtered out.Real case in my DB: 106 sessions in a git worktree directory all had the correct
project_idbutpath = "Users/ivony/slides/ai-biz"instead of"". Fixing onlyproject_id(as the migration does) is not enough —pathhas to be recomputed too.2. Projects are created lazily, so sessions disappear the first time you use the directory
Project rows are not created during migration for every directory; they are created on first location resolve (launching the TUI in that directory, or creating a session there). Non-git directories get their own project as well (deterministic id
sha1("directory:" + dir)).Consequence: a directory's V1 sessions remain visible while the directory still resolves to
global(the list falls back to adirectoryfilter), and vanish from the default view the first time you actually open OpenCode in that directory. So this is not a one-time migration artefact — it silently affects every old directory the first time it is used after the upgrade.Also worth noting:
GET /api/location?location[directory]=<dir>looks read-only but creates the project row as a side effect, which is enough to trigger the above.moveis the fix, but it has a trapPOST /api/session/{id}/movewith{"directory": <the session's own directory>}re-resolves the project and recomputespath, which fixes both cases above. Two gotchas:movedoes not create the target project. If the directory has no project row yet, the request returns204and silently leaves the session onglobal. The project has to exist first (a location resolve does it).movefails withLocationNotFoundError: Directory does not exist, so those sessions cannot be reassigned at all.In my DB that was 244 sessions on the home directory plus 125 more elsewhere (106 stale-
path, 18 directories that stopped being git worktrees, 1 deleted directory); all 550 non-archived sessions are now reachable from their own directory with 0 failures. No data was ever lost —ctrl+a/tabs.scope: "global"always showed them.Suggested fixes
project_id, recomputesubpathfrom the new project at the same time.directoryfor sessions whose project was assigned before the project existed.opencode-agent commentedon Oct 12, 2026
Thanks for digging into the bundle, and for the per-category numbers. They're very useful. I still think this is the same issue as #49827: legacy sessions don't match the project and subpath that the default
cwd-scoped list uses. Your two triggers are already tracked there or in open PRs:pathafterproject_idis rewritten: migrate-v1: sessions created in V1 (global+subpath) hidden from V2 session list #54521 reports the same case (point 2, a V1-era subpath left on real-project sessions), and that issue was folded into migrate-v1: non-git sessions in "global" project hidden after V1→V2 upgrade #49827. Open PR fix(core): attribute migrated V1 sessions to the project of their directory #51935 recomputes the subpath for sessions it moves offglobalduring migration. From its description, it doesn't seem to cover sessions whoseproject_idwas already reassigned but still carry the old path, so that case is worth pointing out there.globalsessions get adopted when the directory is first opened, withpathreset to"".The
movegotchas you found are new information: it returns204and leaves the session onglobalwhen the target project row doesn't exist yet, and it fails withLocationNotFoundErrorfor deleted directories. The same goes forGET /api/locationcreating the project row as a side effect. Could you post this analysis, including the gotchas, as a comment on #49827? That way it stays with the main issue and the PRs.The bot will still close this issue as a duplicate of #49827 unless your problem turns out to be something those issues and PRs don't cover.
opencode-agent commentedon Oct 13, 2026
Closing this as a duplicate of #49827. Legacy V1 sessions end up not matching the project and subpath that the default
cwd-scoped session list filters on, so they're hidden even though the data is intact.Thanks again for the detailed investigation. Please carry your findings over so they aren't lost with this issue:
movegotchas (a silent204when there's no project row,LocationNotFoundErrorfor deleted directories) are worth posting thereIf something here turns out not to be covered by those, reply and we can reopen.