Skip to content

fix(worktree): strip verbatim \?\ path prefix so git accepts worktree paths (Windows)#347

Merged
gnoviawan merged 1 commit into
gnoviawan:devfrom
willy-scr:fix/worktree-verbatim-path
Jun 14, 2026
Merged

fix(worktree): strip verbatim \?\ path prefix so git accepts worktree paths (Windows)#347
gnoviawan merged 1 commit into
gnoviawan:devfrom
willy-scr:fix/worktree-verbatim-path

Conversation

@willy-scr

@willy-scr willy-scr commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Problem

Creating a worktree on Windows fails for every project with:

Git error: Preparing worktree (new branch '…')
fatal: could not create leading directories of
'/?/C:/Users/.../.termul/worktrees/<name>/.git': Invalid argument

The malformed /?/C:/... path is what git.exe makes of a verbatim (extended-length) path it was handed.

Root cause

validate_project_path (src-tauri/src/commands.rs) canonicalizes the project path with std::fs::canonicalize(). On Windows this always returns a path with the \?\ prefix, e.g.:

\?\C:\Users\willy\Documents\OpenMontage

That prefix is then passed straight through to git.exe as a git worktree add argument. Git (MSYS2) cannot parse \?\… and aborts — hence every worktree creation breaks on Windows.

This is a regression from #197 (fix(security): add path validation to worktree commands), which introduced the canonicalize for path-traversal protection.

Unrelated to PR #346 (fix(worktree): self-heal stale git-repo detection) — different root cause, kept as a separate PR.

Fix

Canonicalization is kept for security (symlink resolution + existence check), but the \?\ prefix is stripped from the resulting string before it reaches external tools:

  • path_validation::strip_verbatim_prefix — pure-string rewriter:
    • \?\C:\…C:\…
    • \?\UNC\server\share\server\share
    • normal paths: unchanged (no-op on Unix)
  • validate_project_path applies it, so every validated path (worktree create/list/remove, PTY cwd, …) stays tool-friendly while preserving the canonicalization benefits.

Verification

  • Rust toolchain is not available in my local environment, so I could not run cargo test/cargo check locally. The change is minimal and reviewed by hand.
  • Unit tests added for both prefix shapes + the no-op case (cross-platform string tests).
  • Relying on CI (pr-validation.yml) which runs cargo check --all-targets, cargo test, cargo clippy -- -D warnings, plus a dedicated rust-windows-check job — directly relevant since this is a Windows-only bug. I'll address anything CI flags.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Windows paths are now normalized to remove extended-length prefixes, improving tool compatibility.

… paths

On Windows, std::fs::canonicalize() returns an extended-length ("verbatim")
path with the \?\ prefix (e.g. \?\C:\Users\...). That prefix is passed
straight through to git.exe by worktree commands, which rejects it:

  fatal: could not create leading directories of
  '/?/C:/Users/.../.termul/worktrees/<name>/.git': Invalid argument

This was a regression from the path-traversal security hardening (canonicalize
was added in gnoviawan#197) and made every worktree creation fail on Windows.

- Add path_validation::strip_verbatim_prefix to rewrite \?\C:\... -> C:\... and
  \?\UNC\server\share -> \server\share (pure string, cross-platform).
- Apply it in validate_project_path so all validated paths stay tool-friendly
  while keeping canonicalization's symlink/traversal protections.
- Add unit tests for both prefix shapes and the no-op normal-path case.

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds Windows path normalization to ensure canonicalized project paths are tool-friendly. A new utility function strips Windows verbatim (\\?\) prefixes from paths, and the project path validator integrates it to return normalized paths for IPC commands.

Changes

Windows Verbatim Path Handling

Layer / File(s) Summary
Verbatim prefix stripping helper and tests
src-tauri/src/path_validation.rs
New exported strip_verbatim_prefix function removes Windows extended-length path prefixes (\\?\C:\... and \\?\UNC\...), checking UNC before disk formats, and returning unchanged paths for non-verbatim inputs. Unit tests cover disk prefix stripping, UNC prefix stripping, normal path passthrough, and UNC precedence.
Path validation integration
src-tauri/src/commands.rs
validate_project_path canonicalizes input, applies strip_verbatim_prefix to normalize Windows paths, logs the simplified result, and returns the normalized PathBuf.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • gnoviawan/termul#197: Modifies the same validate_project_path entry point to canonicalize and normalize path inputs for worktree IPC commands.

Poem

🐰 A rabbit hops through Windows paths so deep,
Stripping those pesky prefixes we don't keep,
Verbatim begone, now the canonicals shine,
Tool-friendly paths in a simple design!
✨ Path perfection, refined and lean.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: stripping Windows verbatim path prefixes to fix git worktree path acceptance on Windows.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
src-tauri/src/path_validation.rs (1)

299-306: 💤 Low value

Misleading test name.

The test name suggests disk prefix is chosen over UNC, but the test actually verifies the opposite: that UNC paths are correctly identified and converted to \\server\... rather than being mistakenly matched by the shorter \\?\ prefix and left as UNC\....

Consider renaming to something like test_strip_verbatim_unc_prefix_takes_precedence to match the actual assertion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/src/path_validation.rs` around lines 299 - 306, The test function
name test_strip_verbatim_disk_prefix_chosen_over_unc_match is misleading because
the assertion verifies that UNC verbatim prefix is handled (mapped to
\\server\...) rather than the shorter \\?\ disk prefix; rename the test to a
clear name such as test_strip_verbatim_unc_prefix_takes_precedence by updating
the function identifier and any internal references/usages to that test name so
it matches the asserted behavior (reference: the test function currently calling
strip_verbatim_prefix(r"\\?\UNC\server\share")).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src-tauri/src/path_validation.rs`:
- Around line 299-306: The test function name
test_strip_verbatim_disk_prefix_chosen_over_unc_match is misleading because the
assertion verifies that UNC verbatim prefix is handled (mapped to \\server\...)
rather than the shorter \\?\ disk prefix; rename the test to a clear name such
as test_strip_verbatim_unc_prefix_takes_precedence by updating the function
identifier and any internal references/usages to that test name so it matches
the asserted behavior (reference: the test function currently calling
strip_verbatim_prefix(r"\\?\UNC\server\share")).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 193da85d-441b-4dfc-b5f7-49df3b848bd6

📥 Commits

Reviewing files that changed from the base of the PR and between dc6231e and 034b8a2.

📒 Files selected for processing (2)
  • src-tauri/src/commands.rs
  • src-tauri/src/path_validation.rs

@gnoviawan gnoviawan merged commit 63e68fc into gnoviawan:dev Jun 14, 2026
12 checks passed
gnoviawan added a commit that referenced this pull request Jun 15, 2026
…352)

PR #295 replaced the pty CWD existence check with std::fs::canonicalize,
which on Windows returns a verbatim \?\-prefixed (device-namespace) path.
That string was handed unmodified to cmd.exe via ConPTY; cmd.exe cannot
operate in the device namespace and prints "UNC paths are not supported.
Defaulting to Windows directory", making the shell land in C:\ instead of
the project (regression first released in v0.4.6).

Apply the existing path_validation::strip_verbatim_prefix right after
canonicalize — the exact remedy already shipped for git.exe worktree
paths in #347. Canonicalize still runs, so #295's symlink/traversal
protections are preserved; only the string representation handed to
external tools is normalized to C:\… (no-op off Windows). The cleaned
path flows to the ConPTY spawn cwd, TerminalInstance.cwd, the cwd/git
trackers, and the returned TerminalInfo.

Verified: cargo check + cargo test path_validation (12 tests) + debug build.
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.

2 participants