anomalyco / anomalyco/opencode
V1→V2 migration loses/hides history: corrupt-part migrator 500s, undecodable rows report no field detail, >9k-message imports 500 with empty body, project picker is a hidden shortcut
Open
@jlongster is already working on this.
Since Aug 15, 2026.
2.0
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- Avg merge
- 7h 2m
- Merged PRs (30d)
- 384
Description
Summary
Migrating OpenCode V1 chat history into the V2 desktop beta destroys or hides it: the built-in migrator 500s on a few corrupt legacy rows, sessions written by third-party tools into the V2 tables are silently undecodable, very large sessions can't be imported at all, and there is no discoverable way to open the old sessions (project picker exists only as a hidden keybind).
Environment
- opencode version: 0.0.0-next-17403 (embedded
opencode-cli serve --servicevia OpenCode Beta desktop app), alsoopencode20.0.0-next-17428 - OS: Linux 6.8.0-136-generic (Ubuntu), x86_64
- Terminal: xterm-256color (desktop app is the client used)
- Shell: /bin/bash
- Install/channel: next / beta desktop (Electron,
/opt/OpenCode Beta/ai.opencode.desktop.beta) - Active plugins: none found in config
Reproduction
- Start from a V1 data dir (
~/.local/share/opencode/opencode.dbcontaining legacysession/message/parttables alongside V2session_v2/session_message), with 26 corrupt legacypartrows. - Open the V2 desktop beta; let it run its built-in migration.
GET /api/experimental/migration/v1→500 database disk image is malformed(queryingmessageby a session whosepartrows are corrupt). No partial credit, no user-facing warning — history just looks empty.- Any tool or script that "helps" by writing V1-shaped rows directly into
session_v2/session_messageproduces rows thatSELECTcleanly but fail the runtime decoder:
GET /api/session/<id>/message→500 "failed to decode session message"(log only). POST /api/session/importwith a session of ~13k messages → 500 with empty body; log shows
SQLite query expected 27270 values, received 92806atSessionTransfer.import (../server/src/handlers/session.ts:112). Last safe observed size: 9000 messages.- Even after messages are present and decoding, the beta desktop home/history shows nothing for the project — the project picker (
project.select) exists only as a hidden keybindmod+shift+o(not in Settings), and in the current desktop build that shortcut does nothing when pressed.lastProjectstays pinned to whatever was open on restart, so there is no working way to reach another folder's history from the UI.
Expected Behavior
- Migration should survive a few bad legacy rows (warn + skip that session) and report what failed.
- Records written in a compatible format should either decode or fail with the specific field (the import validator already does this well).
- History, once migrated, should be reachable from the UI without a hidden shortcut.
Actual Behavior
- One corrupt part row aborts the whole migration; the app shows empty history with no error.
- Hand-migrated rows are rejected with only
failed to decode session messageand no field detail (root causes we found: missing top-levelfinish, missingmodel.variant,step-start/step-finishcontent items that don't exist in V2, toolstateusingoutputinstead ofcontent, tool error states needingstate.erroras aSession.StructuredErrorobject). - Sessions >~9k messages cannot be imported (prepared-statement parameter mismatch → silent empty-body 500).
- Migrated history is effectively invisible:
GET /api/sessiondefaults to newest-50 and the app has no discoverable session/folder picker — the only candidate (project.select/mod+shift+o) is declared in the command catalog but non-functional in the desktop build.
Additional Context
- Expected import payload shape that works:
{ "info": Session.Info, "messages": Session.Message.Info[] }— verified end-to-end (1000+ sessions imported, all decode, served via the message endpoint). - Frequency: consistently reproducible across restarts.
- Workaround used: delete the offending V2 rows and re-import each session through
POST /api/session/import, converting V1 part data to the strict V2 shapes; for the two ~13k/18k-message sessions, only the most recent 9000 messages could be imported. - Idempotency note: an import whose
POSTreturns empty-body 500 looks like success to clients;?.dataand error tags are not consistently enforced. - No opencode git checkout was available on the machine, so no exact source refs were inspected; stack path in step 5 came from the server log.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.