Skip to content

After upgrading to OpenCode v1.2.21, previous sessions disappear from the TUI session list. #16579

@cjnova

Description

@cjnova

Description

OpenCode v1.2.21 — Session Migration Fix

Problem

After upgrading to OpenCode v1.2.21, previous sessions disappear from the TUI session list.

Root Cause

v1.2.21 changed how projects are identified:

Version project_id How it works
<= 1.2.20 "global" All directories share one project
>= 1.2.21 <git root commit SHA> Each git repo gets a unique ID based on its first commit

The upgrade creates a new project entry with the git-derived ID, but the built-in migrateFromGlobal() function may fail to reassign existing sessions. Result: 0 sessions visible.

For non-git directories, the global project's worktree changed from the actual path to "/", so sessions stored with the real directory path no longer match.

Diagnosis

1. Locate the database

~/.local/share/opencode/opencode.db

2. Find the new project ID

# Option A: read from git cache
cat .git/opencode

# Option B: compute it yourself (run from the repo)
git rev-list --max-parents=0 --all | sort | head -1

3. Check for orphaned sessions

bun -e "
const { Database } = require('bun:sqlite');
const d = new Database('$HOME/.local/share/opencode/opencode.db', {readonly: true});

// All sessions grouped by project_id and directory
const rows = d.query('SELECT project_id, directory, COUNT(*) as c FROM session GROUP BY project_id, directory ORDER BY c DESC').all();
rows.forEach(r => console.log(r.project_id, '|', r.directory, '|', r.c, 'sessions'));
"

If you see sessions under project_id = 'global' with a real directory path, they're orphaned.

Fix

Close OpenCode before running these.

Case 1: Git-enabled directory

Sessions are under global but should be under the git root commit SHA.

bun -e "
const { Database } = require('bun:sqlite');
const d = new Database('$HOME/.local/share/opencode/opencode.db');

const PROJECT_ID = '<git-root-commit-sha>';  // from: git rev-list --max-parents=0 --all
const DIRECTORY  = '<your-project-path>';     // e.g. /home/user/my-project

const before = d.query(\`SELECT COUNT(*) as c FROM session WHERE project_id = 'global' AND directory = '\${DIRECTORY}'\`).get();
console.log('Sessions to migrate:', before.c);

d.run(\`UPDATE session SET project_id = '\${PROJECT_ID}' WHERE project_id = 'global' AND directory = '\${DIRECTORY}'\`);

const after = d.query(\`SELECT COUNT(*) as c FROM session WHERE project_id = '\${PROJECT_ID}'\`).get();
console.log('Sessions under new project_id:', after.c);
d.close();
"

Case 2: Non-git directory

Sessions have the real directory path but the global project now expects "/".

bun -e "
const { Database } = require('bun:sqlite');
const d = new Database('$HOME/.local/share/opencode/opencode.db');

const DIRECTORY = '<your-directory-path>';  // e.g. /home/user/notes

const before = d.query(\`SELECT COUNT(*) as c FROM session WHERE project_id = 'global' AND directory = '\${DIRECTORY}'\`).get();
console.log('Sessions to fix:', before.c);

d.run(\`UPDATE session SET directory = '/' WHERE project_id = 'global' AND directory = '\${DIRECTORY}'\`);
console.log('Fixed. Sessions now accessible under global project.');
d.close();
"

Verification

bun -e "
const { Database } = require('bun:sqlite');
const d = new Database('$HOME/.local/share/opencode/opencode.db', {readonly: true});

const orphans = d.query(\"SELECT project_id, directory, COUNT(*) as c FROM session WHERE project_id = 'global' AND directory != '/' GROUP BY project_id, directory\").all();
if (orphans.length === 0) {
  console.log('No orphaned sessions. All good.');
} else {
  console.log('Remaining orphans:');
  orphans.forEach(o => console.log(o.directory, ':', o.c, 'sessions'));
}
d.close();
"

Notes

  • Child sessions (subagent tasks) have a parent_id set — the TUI only shows top-level sessions, so the count may look lower than expected
  • The .git/opencode file caches the project ID so it doesn't run git rev-list on every startup
  • If a repo has multiple root commits (e.g. after a --allow-unrelated-histories merge), opencode sorts them and picks the first
  • No sqlite3 needed — bun:sqlite is built into bun

Upstream References

  • PR #16389 — fix for project ID cache and worktree session loss (open)
  • Issue #16506 — Drizzle migration name mismatch crash on v1.2.21
  • Issue #15719 — non-git directory shows "/" as project
  • Source: packages/opencode/src/project/project.tsmigrateFromGlobal() and fromDirectory()

Plugins

OmO

OpenCode version

1.2.21

Steps to reproduce

After upgrading to 1.2.1 all sessions disappear from TUI. Even the global ones with no git.

Screenshot and/or share link

No response

Operating System

Ubuntu 24.04 inside WSL2

Terminal

Windows Terminal

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingcoreAnything pertaining to core functionality of the application (opencode server stuff)windows

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions