Skip to content

Error instead of silently failing when browsing an unreachable environment#4590

Open
colonelpanic8 wants to merge 2 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/error-on-unreachable-environment-browse
Open

Error instead of silently failing when browsing an unreachable environment#4590
colonelpanic8 wants to merge 2 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/error-on-unreachable-environment-browse

Conversation

@colonelpanic8

@colonelpanic8 colonelpanic8 commented Jul 26, 2026

Copy link
Copy Markdown

What Changed

The add-project browser (⌘K → Add project → Local folder) resolves paths on the selected environment's filesystem via filesystemEnvironment.browse, but never read that query's error. This adds an explicit availability check and fails closed instead of failing silently.

  • New pure resolveBrowseAvailability in CommandPalette.logic.ts maps the environment's connection phase (available / offline / connecting / reconnecting / error / connected) onto an Available | Unavailable { message } verdict, carrying the underlying reason when there is one. It is keyed on reachability only — a browse failure on a reachable host means the path does not exist yet (the server returns read_directory_failed for a missing parent), which is exactly the Create & Add case, so it must not gate submission.
  • The browse RPC is no longer issued at all unless the environment is connected.
  • canSubmitBrowsePath is false when unavailable, which disables the Enter path, the submit button, and the clone-destination step (they share it). This also withholds the "create this folder and add it as a project" affordance, so the UI can never offer to create a directory on a host it failed to inspect.
  • The reason renders in the results empty state instead of a blank list.
  • handleAddProjectForEnvironment refuses with an explicit toast when the target environment is not connected, reusing the same verdict so the toast states the reason rather than a bare status word. This is the layer that covers the desktop folder-picker entry point, which bypasses the browse UI entirely.
  • ChatComposer's @-path mention search dropped its error the same way, so an unreachable environment rendered "No matching files or folders." That reads as a definitive answer to a question we never got to ask; it now surfaces the actual failure.

Why

Browsing resolves paths on a machine that may not be reachable, so "no entries" and "could not ask" are very different answers that looked identical.

Reproduced against a paired remote environment that was then killed: the palette rendered an empty Directories group indistinguishable from an empty directory, showed no reason anywhere, and left the Add button enabled. Pressing Enter did nothing at all — no toast, no error, no state change. The failure was entirely invisible.

FileBrowserPanel and FilePreviewPanel already render .error for project file reads, so the add-project browser and the composer path search were the outliers rather than the convention.

UI Changes

Both captures are the same flow — Add project → the remote environment → Local folder~/ — against a paired remote whose backend was killed.

Before After
Add-project browser against an unreachable environment: an empty "Directories" group, no error text, and an enabled Add button Same flow showing "Reconnecting to railbird-sf. Reason: Failed to fetch remote environment endpoint ..." with the Add button disabled

Before: empty list, no reason, Add enabled, Enter silently does nothing.
After: Reconnecting to railbird-sf. Reason: Failed to fetch remote environment endpoint http://127.0.0.1:47319/.well-known/t3/environment (HttpClientError: Transport error ...), Add disabled.

Verified live in the web app against two t3 serve instances: the second was paired as a remote environment, confirmed Connected, then killed to produce the unreachable state.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • No animation/interaction change, so no video

Validation:

  • vp test run apps/web/src/components/CommandPalette.logic.test.ts (14 tests, 9 new)
  • vp run --filter @t3tools/web typecheck (no errors in changed files)
  • vp lint on all four changed files (no new findings)
  • vp fmt --check on all four changed files

Note

Low Risk
UI and client-side guardrails around filesystem browse/add flows; no auth or data-model changes, with behavior covered by new unit tests.

Overview
Unreachable environments no longer look like empty folders when adding projects or searching @ paths.

Adds resolveBrowseAvailability to map environment connection phase (and optional connection error text) to Available vs Unavailable messages. Browse stays available when connected even if directory read fails (so “create folder & add” still works).

In the command palette add-project browse flow, the filesystem browse RPC runs only when the target environment is connected; otherwise the results area shows the availability message, directory lists are hidden, and Add / Create & Add / clone destination submission is disabled. handleAddProjectForEnvironment (including the native folder picker) shows an error toast with the same message instead of attempting the add.

ChatComposer @ path search now shows the workspace lookup error in the empty menu state instead of “No matching files or folders.”

Reviewed by Cursor Bugbot for commit 429e392. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Show error instead of silently failing when browsing an unreachable environment

  • Adds resolveBrowseAvailability in CommandPalette.logic.ts that returns an Available/Unavailable verdict with a user-facing message based on the environment's connection phase and error reason.
  • The command palette skips filesystem browse queries, hides browse lists, and disables path submission when the selected environment is not connected.
  • Adding a project via handleAddProjectForEnvironment now shows a toast error with a specific availability message instead of attempting an operation that will fail.
  • The chat composer's path search menu surfaces the actual error message instead of the generic "No matching files or folders."

Macroscope summarized 429e392.


Review follow-up (429e392)

Bugbot caught two issues on the first commit; both are fixed.

Browse errors blocked folder creation (high). Real regression, and my fault for unit-testing that branch instead of exercising it. WorkspaceEntries.browse only swallows EACCES/EPERM to an empty listing — ENOENT propagates as read_directory_failed. Treating that as Unavailable made canSubmitBrowsePath false, so Create & Add could never create a folder that did not already exist. Availability is now keyed on connection phase alone. Verified end to end: on a connected environment ~/brand-new-folder-xyz/ shows an enabled Create & Add, and Enter creates the directory and adds the project. Regression test added pinning connected + browse error to Available.

Toast used status, not reason (medium). connectionStatusText renders the bare phase word, so the refusal really did read "Failed to add project — Available". The guard now reuses the availability verdict and reads " isn't connected."

…ble environment

The add-project browser resolves paths on the selected environment's
filesystem, but never read the browse query's error. Against an environment
the client cannot reach, the result is a silent dead end: the directory list
renders an empty "Directories" group that is indistinguishable from an empty
directory, no reason is shown anywhere, and the submit button stays enabled —
pressing Enter then does nothing at all, with no feedback.

Add `resolveBrowseAvailability`, which maps the environment's connection
phase plus any browse error onto an explicit availability verdict, and use it
to fail closed:

- the browse RPC is not issued unless the environment is connected;
- `canSubmitBrowsePath` is false when unavailable, disabling the Enter path,
  the submit button, and the clone-destination step. This also withholds the
  "create this folder and add it as a project" affordance, so the UI can
  never offer to create a directory on a host it failed to inspect;
- the reason renders in the results empty state instead of a blank list.

`handleAddProjectForEnvironment` also refuses with an explicit toast when the
target environment is not connected, which covers the desktop folder-picker
entry point that bypasses the browse UI entirely.

The composer's @-path mention search dropped its error the same way, so an
unreachable environment rendered "No matching files or folders" — a
definitive-sounding answer to a question we never got to ask. It now surfaces
the actual failure.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0b0e1869-16f6-41f0-95af-fda8f3f96737

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ 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.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 26, 2026

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

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 93f2a23. Configure here.

Comment thread apps/web/src/components/CommandPalette.tsx
Comment thread apps/web/src/components/CommandPalette.logic.ts Outdated
@macroscopeapp

macroscopeapp Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved

This is a well-scoped UX improvement that adds proper error messages when browsing an unreachable environment. The changes are self-contained with comprehensive test coverage, involving pure logic additions and UI error display without modifying core business logic.

You can customize Macroscope's approvability policy. Learn more.

colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 26, 2026
…rowsing an unreachable environment)

# Conflicts:
#	apps/web/src/components/CommandPalette.logic.test.ts
#	apps/web/src/components/CommandPalette.tsx
colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 26, 2026
Adds pingdotgg#4590 to the thread-picker group rather than the main
manifest: it edits the same CommandPalette trio, and specifically the
browse/submit region that pingdotgg#4257 and pingdotgg#4426 also touch, so the combination
resolves once against upstream main instead of being re-derived every refresh.

Group rebuilt (reproduce) to b15922f and repinned in stack.toml; main stack
refreshed. The group rebuild reproduced tree bad6ae3 across two independent
runs, and the assembled tree keeps every pingdotgg#4590 gating site plus the composer
path-search error.

The one non-mechanical resolution: the group had already extracted the palette
empty-state ternary into `contextualEmptyStateMessage` +
`resolveCommandPaletteEmptyStateMessage`, so pingdotgg#4590's inline branch was rewritten
onto that helper instead of taking either side verbatim.
…se errors

Review caught a regression in the previous commit: treating any browse error as
Unavailable made canSubmitBrowsePath false, which killed Create & Add on a
perfectly reachable host.

The server returns read_directory_failed whenever readdir on the parent fails,
and only EACCES/EPERM are swallowed to an empty listing -- ENOENT propagates.
So typing a folder that does not exist yet, which is precisely what Create &
Add exists for, produced a browse error and the new gate refused to submit.
Verified end to end: on a connected environment "~/brand-new-folder-xyz/" now
shows an enabled "Create & Add", creates the directory, and adds the project.

Availability is now derived from the connection phase alone. A browse failure
on a reachable host says nothing about whether the environment can be reached,
so it no longer participates.

Also drop connectionStatusText from the add-project guard. It renders the bare
phase word, so refusing an add against a non-connected environment produced
"Failed to add project — Available". The toast now reuses the same availability
verdict as the browser and reads "<environment> isn't connected."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant