Skip to content

[Bug]: Diff panel Working tree/Branch scopes silently empty for every in-place project — getDiffPreview workspace-root guard compares against $HOME in packaged desktop builds #4022

Closed

Description

@mikeohuo

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. Install a packaged desktop build (stable 0.0.28, Windows installer). In packaged builds the backend server is spawned with cwd = $HOME (apps/desktop/src/app/DesktopEnvironment.ts: backendCwd: input.isPackaged ? homeDirectory : appRoot — documented in [Bug]: Packaged builds set server cwd to $HOME; ClaudeProvider auxiliary spawns leak it past project bindings #2867), and the spawn passes no --cwd flag, so ServerConfig.cwd resolves to process.cwd() = the home directory. Verified on the live process: the backend child's cwd is C:\Users\T9.
  2. Add any project whose repo lives outside the home directory (e.g. D:\git\<repo>) and run a thread in place (not in a t3-managed worktree).
  3. Open the diff panel and switch the scope dropdown to Working tree or Branch changes.

Expected behavior

The panel shows the working-tree / branch diff of the project's repository, as those scopes describe.

Actual behavior

The panel silently renders empty for every in-place project, regardless of repo size or state. Two-step failure:

  1. ReviewService.getDiffPreview calls assertWorkspaceBoundCwd, which only accepts a cwd inside ServerConfig.cwd or config.worktreesDir. Since ServerConfig.cwd is $HOME in packaged builds, the project cwd (D:\git\<repo>) is rejected in ~2 ms:

    VcsRepositoryDetectionError: VCS repository detection failed in ReviewService.getDiffPreview: D:\git\ABW\game - Review diff preview cwd must stay within the configured workspace root.

  2. The client already knows about this failure mode — apps/web/src/components/DiffPanel.tsx has a dedicated fallback:

    const shouldRetryBranchDiffAtEnvironmentCwd =
      primaryBranchDiffPreview.error?.includes("configured workspace root") === true &&
      serverConfig?.cwd !== undefined &&
      serverConfig.cwd !== activeCwd;

    The retry re-queries with cwd: serverConfig.cwd — i.e. it computes the diff preview against $HOME, which is not a git repository, so the query "succeeds" with no sources and the panel shows nothing. No error ever surfaces to the user.

The only cwds that can pass the guard are t3-managed worktrees under ~/.t3/worktrees, so Working tree / Branch changes scopes only function for worktree threads. On large monorepos this leaves the diff panel with no working scope at all, because the Turn scopes are independently broken there by the checkpoint-capture timeout (#3646).

The guard itself is well-motivated — it's the validation added after #316 (arbitrary client-supplied cwd). The problem is that it validates against the server process's cwd, which in packaged desktop builds is $HOME by design, rather than against the workspace roots of registered projects. #2867 reports the same $HOME-cwd root cause from the provider-probe side; #2441 looks like this same silent-empty diff panel observed without the root cause identified.

Impact

Major degradation or frequent failure

Version or commit

0.0.28 (desktop stable, Windows installer); code paths verified identical at main @ ecb35f7

Environment

Windows 11 Pro (10.0.26200), T3 Code desktop 0.0.28, git 2.54.0.windows.1, provider claudeAgent

Logs or stack traces

server.trace.ndjson — the two spans emitted by one open of the diff panel (primary + fallback):

19:10:13  ws.rpc.review.getDiffPreview  2.0 ms   Failure
  VcsRepositoryDetectionError: VCS repository detection failed in
  ReviewService.getDiffPreview: D:\git\ABW\game - Review diff preview cwd
  must stay within the configured workspace root.
      at .../app.asar/apps/server/dist/bin.mjs:37040:17

19:10:13  ws.rpc.review.getDiffPreview  437.2 ms Success   (fallback at serverConfig.cwd = C:\Users\T9 — not a repo, empty result)

Backend spawn (no --cwd; ServerConfig falls back to process.cwd()):
  "...\t3code\T3 Code (Alpha).exe" ...\app.asar\apps\server\dist\bin.mjs --bootstrap-fd 3
  live process cwd: C:\Users\T9

Workaround

Run the thread in a t3-managed worktree (paths under ~/.t3/worktrees pass the guard). No workaround exists for in-place projects. Suggested direction: validate getDiffPreview's cwd against the registered projects' workspace roots (and thread worktree paths) instead of ServerConfig.cwd, or have the desktop app pass the project roots to the server as allowed boundaries — this would fix the diff panel while keeping the #316 hardening intact. The DiffPanel.tsx fallback should also surface an error instead of silently rendering an empty diff of the wrong directory.

Activity

  1. t3dotgg commented on Aug 27, 2026

    @t3dotgg
    Member

    Related report #5616 covers the same problem and adds useful evidence.

    The August 10 runtime trace confirms the same cause as issue #4022: the registered WSL repository is outside the server startup cwd, ReviewService rejects it, and DiffPanel silently retries an unrelated directory. This is an exact duplicate of that path-validation bug, not a Git invocation problem.

    I'm linking the report here before I close it as a duplicate during an automated pass. The source report and its attachments will remain available at #5616.

  2. nbros commented on Sep 13, 2026

    @nbros

    The August 10 runtime trace confirms the same cause as issue #4022: the registered WSL repository is outside the server startup cwd, ReviewService rejects it, and DiffPanel silently retries an unrelated directory. This is an exact duplicate of that path-validation bug, not a Git invocation problem.

    It's not only related to WSL on Windows : I'm having the same issue on macOS.
    With T3 Code 0.0.40 on macOS 26.6.2, using a remote connection to another macOS machine.
    I'm using t3 connect:

    %  npx t3@latest service status
    T3 Code service
      Status: installed · t3@0.0.40
    

    My Working tree diff panel displays “No patch available for this selection,” while git status confirms I do have changes.

    The server trace confirms the same error:

    VcsRepositoryDetectionError:
    VCS repository detection failed in ReviewService.getDiffPreview:
    /Users/Shared/git/karaoke -
    Review diff preview cwd must stay within the configured workspace root.
    

    The project path and the git path are already exactly the same though! ("configured workspace root" is the project path right?)

    But I've noticed similar issues in VS Code where it handled paths in a case sensitive manner even on macOS where case is insensitive by default.

    Image
  3. kyledevans commented on Sep 25, 2026

    @kyledevans

    Still reproduces on 0.0.43-nightly.20260922.2096, native Windows 11 (no WSL), project at C:\dev\repos\my-app, outside %USERPROFILE%. Same trace: the first review.getDiffPreview fails with "cwd must stay within the configured workspace root", the fallback at C:\Users\<me> succeeds with empty sources, and Working tree / Branch changes are both blank.

    There's an open fix for exactly this in #8559 (it references #8506, which is the same bug).

  4. saphid commented on Oct 2, 2026

    @saphid
    Contributor

    Routing: Do not open a duplicate. #4022 already identifies this exact boundary failure and has a maintainer duplicate confirmation. #8506 has related client evidence. The equivalent #8559 is closed, not merged. Request agreement on the root boundary under the existing report before a substantial fix; report confirmation is not blanket approval to accept arbitrary paths or all descendants.

    Environment and verification limits

    Research date: 2026-10-03. Fetched origin/main successfully; target: 7ff2eabf56. Local research host: macOS / Darwin 25.5.0 arm64, Node v24.12.0, gh 2.94.0. Main pins Effect 4.0.0-rc.115. This lane used read-only source comparisons and existing evidence; it did not launch a server, browser, desktop app, or live forge checkout. Historical regression results below are explicitly historical, not fresh runtime reproductions on this SHA. Source fingerprints and exact verification scope are in verification.json.

    Exact reproduction on current main

    1. Use two disposable sibling directories A and B, neither inside the server's managed worktrees directory. Initialize B as a Git repository, commit a tracked text file, and edit it after committing.
    2. Start current main's server with launch cwd A and an isolated development home. Ensure the resolved ServerConfig.cwd is A, not an ancestor of B. Register B as a project in the client.
    3. Create/select a thread in B using the current checkout, rather than a managed worktree.
    4. Open its Diff panel and select Working tree or Branch changes. Confirm B's git diff is nonempty.
    5. Inspect the review.getDiffPreview RPC trace. Its first request has cwd B and fails the workspace boundary check. On web/desktop, the current DiffPanel retries at the server cwd A; if A is not a Git repo, the retry returns empty sources and the panel appears empty. If A is another repo, the retry can show A's diff instead.
    6. A direct review.getDiffFileContents request for B fails the corresponding file-content boundary check as well. A control request from inside A or the managed worktrees root passes validation.

    Actual versus expected

    Actual: VcsRepositoryDetectionError with “Review diff preview cwd must stay within the configured workspace root.” The file-content equivalent says “Review diff file contents cwd must stay within the configured workspace root.” The client fallback can hide the failure behind an empty or wrong-repository diff. Expected: a permitted registered project can review its own checkout even outside the server launch cwd; requests for unrelated/unregistered paths remain rejected.

    User impact

    Review is unavailable or misleading for legitimate in-place projects on another directory/volume or remote server. Managed-worktree use may avoid the guard. The existing issue includes Windows desktop traces and a macOS remote-server report, so this is broader than Windows. Web and desktop share the fallback; mobile's handling should be checked separately when implementing the same server-boundary correction.

    Current-main verification

    • The entire ReviewService.ts is byte-for-byte unchanged from the P19 reproduction baseline. assertWorkspaceBoundCwd accepts only canonical config.cwd and config.worktreesDir; it never checks project registration.
    • Current DiffPanel.tsx still retries boundary failures using serverConfig.cwd, then selects that fallback as the displayed branch diff.
    • Fresh existing test run: CI=true TMPDIR=<C>/test-tmp vp test run apps/server/src/review/ReviewService.test.ts, exit 0, 4/4 tests passed. The executed ReviewService source and test file were verified byte-for-byte against fetched main. These tests confirm outside-root rejection and operation-specific error text; they do not exercise the proposed registered-project exception.
    • Today's main uses orchestration v2. The older fix's ProjectionSnapshotQuery.getProjectShells integration is stale; the current metadata-only project read surface is ProjectStoreV2 (findActiveByWorkspaceRoot / listShells). Do not port the old service wiring unchanged.

    Source: apps/server/src/review/ReviewService.ts; apps/web/src/components/DiffPanel.tsx; apps/server/src/orchestration-v2/ProjectStore.ts.

    Minimal proposed fix scope — no implementation

    Agree that active registered project roots are an allowed review boundary, then extend validation only to that agreed set while retaining canonicalization, symlink-escape rejection, removed-registration rejection, and fail-closed query errors. Clarify whether nested cwd paths are needed; exact-root access is sufficient for this repro. Read current project metadata without repository-enrichment or a full snapshot rebuild, and retain the fast path for already allowed roots. Ensure the client does not replace a genuine rejection with another repository's diff; this fallback is part of the same incorrect-project review behavior. No arbitrary filesystem access, unrelated diff features, or new user-facing configuration.

    Evidence available

    • Public #4022 includes failing and fallback RPC traces, with Windows and macOS confirmations. Related #8506 and closed #8559 include earlier client screenshots; they are not screenshots of today's main or this lane's branch.
    • Historical P19-before.log: exit 1, 3 failed / 5 passed on the earlier baseline. P19-after.log: exit 0, 8 passed on the earlier proposed branch, covering registration removal/nesting/symlink escape.
    • Fresh current-main-review-test.log, verification.json, and existing-issue-4022.json.
    • No fresh web/desktop screenshots or live remote pass were captured here. Capture before/after for any eventual implementation.

    🤖 Generated with Claude Code

  5. nbrosei commented on Oct 3, 2026

    @nbrosei

    Diffs are still broken in t3 code 0.0.45 (6c8fed3).
    This "working tree" diff view has never worked for me at all in t3 code.

    Image
  6. nbros commented on Oct 3, 2026

    @nbros

    Reproduced on T3 Code 0.0.45, using macOS desktop connected over SSH to a macOS server.

    The t3 code server starts in /Users/claude, while the registered project is /Users/Shared/git/t3code. Diff → Working tree shows “No patch available for this selection,” although git diff HEAD in that checkout shows changes.

    Remote traces confirm:

    VcsRepositoryDetectionError:
    Review diff preview cwd must stay within the configured workspace root.
    

    The validation rejects the registered project because it is outside the server’s startup directory. The UI then silently retries against /Users/claude, which isn’t a Git repository, masking the error.

    Whereas a local checkout under ~/git/t3code works.

    This also affects remote background-service environments, beyond the packaged Windows desktop case originally reported.

  7. saphid commented on Oct 3, 2026

    @saphid
    Contributor

    Thanks for the remote repro. That matches the cause exactly: the registered project is outside the server's startup directory, review validation rejects it, and the client silently falls back to the server cwd.

    #15014 fixes this case. It lets review reads use any registered project root (and its subfolders), not just the launch directory. Symlink escapes and removed projects are still rejected. It isn't tied to the Windows desktop path, so it should cover SSH and background-service environments like yours. If you're able to try that branch on your setup, a confirmation there would help.

  8. nbros commented on Oct 4, 2026

    @nbros

    @saphid Thanks! I verified your fix on my setup with a server starting in /Users/claude, while the registered project lives at /Users/Shared/git/t3code. The remote review API now returns that project’s actual changes and the Diff panel shows the working tree changes.

    For clarity, I asked Codex to backport #15014 at 8a17f359 onto stable v0.0.45, adapting the project lookup to V1 persistence to avoid the V2 migration which I'm avoiding at the moment (I prefer staying on stable atm).
    So I haven’t tested your exact full PR branch unchanged, but at least the backported fix resolves my reported case.
    Thank you!

  9. added 2 commits that reference this issue on Oct 6, 2026
    e92802d
    386e77d
  10. pablo-kitz commented on Oct 8, 2026

    @pablo-kitz

    Still reproducing on 0.0.46-nightly.20261007.2787 on Windows desktop, with both the WSL Ubuntu backend and native Windows environment (observed October 8, 2026).

    Diff counts are visible, but opening Uncommitted changes or Branch changes displays “No patch available for this selection.” Standard Git commands confirm the repository contains changes.

    WSL evidence

    The registered repository is /home/pablo/code/repo, while the backend process starts in /mnt/c/Users/<user>.

    The server trace records:

    VcsRepositoryDetectionError:
    VCS repository detection failed in ReviewService.getDiffPreview:
    /home/pablo/code/repo -
    Review diff preview cwd must stay within the configured workspace root.
    

    Capturing Git process arguments while reopening the diff panel confirms the fallback checks the unrelated startup directory:

    git -C /mnt/c/Users/<user> rev-parse --is-inside-work-tree
    

    That directory is not a Git repository. Running the equivalent command against /home/pablo/code/aleph-kit, using the backend process's environment, returns true.

    The installed runtime's ReviewService.assertWorkspaceBoundCwd still validates against config.cwd and managed worktree directories. Its DiffPanel still retries at serverConfig.cwd when the primary request reports the configured-workspace-root error. This masks the original validation failure with an empty preview.

    Native Windows evidence

    The Windows backend trace independently contains:

    VcsRepositoryDetectionError:
    VCS repository detection failed in ReviewService.getDiffPreview:
    D:\code\pagebuilder -
    Review diff preview cwd must stay within the configured workspace root.
    

    Additional symptom

    The turn/checkpoint selection also shows “No patch available for this selection” on my setup. The investigation above confirms the cause for working-tree/branch previews; it has not established that the checkpoint symptom has the same cause.

    No local runtime patches or configuration changes were applied during diagnosis. This confirms the registered-project-root restriction and silent fallback remain reproducible in the above nightly build.

  11. added 2 commits that reference this issue on Oct 8, 2026
    c13d191
    9d8a8ad
  12. saphid commented on Oct 9, 2026

    @saphid
    Contributor

    Thanks for the detailed trace. That nightly doesn't include the fix yet: #15014 is still open, waiting on maintainer review. Your WSL case matches what it fixes. The registered project /home/pablo/code/repo sits outside the directory the backend started in (/mnt/c/Users/<user>), so the old workspace-root guard rejects it. #15014 checks against registered project roots instead.

    I haven't verified the native Windows environment with #15014. Path comparison there (drive letters, case, separators) wasn't part of its tests. If the native Windows trace shows the same "must stay within the configured" error, please paste the two paths it compares, and I'll check them against the fix.

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

Metadata

Metadata

Assignees

No one assigned

    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