Skip to content

fix(core): resolve relative directories during V1 migration - #57618

Merged
rekram1-node merged 7 commits into
anomalyco:devfrom
MohammadAlMasalmeh:fix-migration-paths
Oct 21, 2026
Merged

rekram1-node merged 7 commits into
anomalyco:devfrom
MohammadAlMasalmeh:fix-migration-paths

Conversation

@MohammadAlMasalmeh

@MohammadAlMasalmeh MohammadAlMasalmeh commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Issue for this PR

Fixes #57602

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Problem. Old ACP sessions in the V1 session table can have directory = '.'. The V1→V2 migration copies that value into session_v2, then reads it back through directoryColumn, which throws Path is not absolute: .. The transaction rolls back along with the cursor update, so the migration retries the same row on every launch and never finishes.

Change. Before the copy, a directory that isn't a stored absolute path is replaced with the session's project worktree. A relative V1 directory was relative to the ACP process's working directory at the time, which we can't recover, so the worktree is the best available stand-in. The original V1 row is left unchanged.

 for each V1 session (newest first)
   pick projectID (missing project → global)
+  if directory is empty or a stored absolute path
+    keep it
+  else
+    use the project worktree (or "" if the worktree isn't absolute either)
+    log "Replaced relative V1 session directory"
   copy row into session_v2 with that directory
   read it back through directoryColumn   ← used to throw here

The migration and directoryColumn share one check, so they can't drift apart:

 database/path.ts
-  absolute(input)            # private: normalize + validate, throw if relative
+  storedAbsolutePath(input)  # exported: normalized path, or undefined if relative
+  absolute(input)            # throws when storedAbsolutePath returns undefined
 database/v1-migration.bun.ts
+  uses storedAbsolutePath for the session directory and the worktree

storedAbsolutePath normalizes backslashes the same way the column does, so Windows paths like C:\repo are still kept on Windows hosts.

Out of scope

  • importNextDatabase copies directories from opencode-next.db without this check. That database has validated paths on write since it was created, so it's left alone here.
  • The path (subpath) column is copied unchanged. Old ACP sessions predate that column, so it should be empty for the affected rows.

How did you verify your code works?

From packages/core on macOS:

bun test test/v1-migration.test.ts test/database-migration.test.ts   # 54 pass, 0 fail
bun test test/database.test.ts test/database-drizzle.test.ts test/database-migration.test.ts test/file-access-path.test.ts   # 51 pass, 0 fail
bun typecheck

New tests cover ., src, Windows-style and UNC worktrees, absolute directories that must be kept, empty directories, a non-absolute worktree, and . in a session whose project is missing. With the fix reverted, the relative-directory cases fail. The Windows-host behavior (backslash paths kept) was checked with a probe script that sets process.platform, not on a Windows machine.

Screenshots / recordings

No UI changes.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Added by the opencode bot (AI-generated).

Related: #54736, #54009

@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I reproduced #57602 on the base by running the issue's script from source: every restart fails with Path is not absolute: . and the migration cursor never moves. With this PR, the . session is resolved against its project's saved worktree (/ for the global project), the warning is logged, the migration reaches completed, and the next restart does nothing. v1-migration.test.ts passes (36/36) and packages/core passes its type check.

I also checked that project worktrees are already stored with forward slashes (20260601010001_normalize_storage_paths), so looking only for X:/ and // is enough to pick the Windows path rules. The original V1 rows are left unchanged.

Public API: unchanged. This only affects the internal V1→V2 data migration.

No blocking concerns.

Related: #54736, #54009

@MohammadAlMasalmeh

Copy link
Copy Markdown
Contributor Author

@rekram1-node i'm ready

@rekram1-node

rekram1-node commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Thanks for the fix and the clear repro! I pushed a follow-up commit (33aefd1) to simplify it a bit:

  • Relative directories now become the project worktree. I dropped the migrateDirectory resolver. A relative V1 directory was relative to the ACP process's cwd, which we can't know, so resolving src against the worktree is no more accurate than using the worktree itself. The only values seen in reports are ".".
  • Removed the backslash and drive-relative handling. The 20260601010001_normalize_storage_paths migration already rewrites C:\… and \\server\… paths in the V1 session and project tables to forward slashes before this code runs. C:child and \child never come up in practice.
  • Reused isWindowsStoragePath from database/path.ts so this check matches what the read path enforces.
  • Restored the existing tests that were changed (including the apostrophe regression test name). New coverage is now a table test plus your missing-project "." case.

The PR description still mentions the Windows/drive normalization, so it should be updated to match.

@rekram1-node
rekram1-node merged commit c3b613c into anomalyco:dev Oct 21, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

migration: V1→V2 data migration permanently stalls on legacy session row with directory='.'

2 participants