Skip to content

[Bug] Tauri v1 migration silently discards all historical session data in workspace .dat files #27431

Closed as not planned

Description

@enjoyless

Bug Description

After upgrading OpenCode to v1.14.48 (Tauri v1 migration), all historical session data was silently lost. The left sidebar in the desktop app shows no conversation history, even though session data exists in the old-format workspace .dat files.

Root Cause

The Tauri migration process (observed in main.log) reads entries from the old Electron storage and writes them to the new JSON-based .dat files. However, all session entries were skipped during migration while only workspace-level entries were preserved.

Evidence from migration log:

tauri migration: migrated opencode.workspace.Qzpc.vtnkm7.dat -> opencode.workspace.Qzpc.vtnkm7.dat {
  migrated: [],
  skipped: [
    'session:ses_xxx:prompt',
    'session:ses_xxx:comments',
    ... 40+ session entries skipped
  ]
}

Additional Issue: Workspace File Fragmentation

After migration, the same workspace (C:) has three separate .dat files:

  • opencode.workspace.C--.hmddcc.dat (new active file, ~400 bytes, nearly empty)
  • opencode.workspace.C--.1dj3o45.dat (older file)
  • opencode.workspace.Qzpc.vtnkm7.dat (old base64-encoded name, contains all historical session data)

The old session data sits in Qzpc.vtnkm7.dat but the app only reads from C--.hmddcc.dat, making historical sessions invisible.

Environment

  • OpenCode version: 1.14.48 (Windows x64)
  • OS: Windows 11
  • Install method: Desktop installer

Expected Behavior

Session history from before the migration should be preserved and visible in the left sidebar.

Actual Behavior

  • Left sidebar shows no conversation history
  • Old session data exists in Qzpc.vtnkm7.dat but was not migrated to the active workspace file
  • Migration log shows all session entries as "skipped" with migrated: []

Workaround

Manually merging session entries from the old .dat file into the current one recovers the session list (but prompt content was already empty in the old data, so conversation titles may not appear).

Please investigate the migration script to ensure session entries are migrated alongside workspace entries.

Activity

  1. 21pounder commented on May 14, 2026

    @21pounder
    Contributor

    I looked into this and can confirm the root cause.

    Root cause

    The migration code in packages/desktop/src/main/migrate.ts uses the old .dat filename directly as the electron-store name:

    // migrate.ts:51
    const storeName = filename === "opencode.settings.dat" ? "opencode.settings" : filename

    So opencode.workspace.Qzpc.vtnkm7.dat gets migrated into a store named opencode.workspace.Qzpc.vtnkm7.dat.

    But the app never reads that store. The workspace store name is generated in packages/app/src/utils/persist.ts using a completely different scheme:

    // persist.ts:337-341
    function workspaceStorage(dir: string) {
      const head = (dir.slice(0, 12) || "workspace").replace(/[^a-zA-Z0-9._-]/g, "-")
      const sum = checksum(dir) ?? "0"
      return `opencode.workspace.${head}.${sum}.dat`
    }
    // called with pathKey(dir), e.g. "C:/" → head="C--", giving "opencode.workspace.C--.hmddcc.dat"

    The old Tauri app encoded the workspace path as base64 in the filename (Qzpc = base64 of C:\). The new Electron app uses pathKey(dir) + FNV checksum. These two schemes produce different filenames for the same workspace, so the migrated data lands in a store the app never opens.

    The session keys (session:ses_xxx:prompt, etc.) appear in skipped in the log because the migration ran against the correct old file, but wrote into the wrong target store — and on a second run the tauriMigrated flag prevents it from running again.

    Fix

    The migration needs to decode the old base64 workspace filename back to a path, then remap it to the new workspaceStorage(pathKey(path)) name before writing. Something like:

    // In migrateFile(), before getStore():
    let storeName = filename === "opencode.settings.dat" ? "opencode.settings" : filename
    
    // Remap old base64-encoded workspace filenames to the new format
    const workspaceMatch = filename.match(/^opencode\.workspace\.([^.]+)\.[^.]+\.dat$/)
    if (workspaceMatch) {
      try {
        const decoded = base64Decode(workspaceMatch[1])  // "Qzpc" → "C:\"
        const key = pathKey(decoded)
        storeName = workspaceStorage(key)
      } catch {
        // not a base64 name, keep original
      }
    }

    This ensures the session data lands in the store the app actually reads.

  2. github-actions commented on Jul 14, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions