fix(desktop,host-service): translate expected errors at throw sites, keep the Sentry boundary dumb
Why
Re-enabling the desktop Sentry key exposed ~140 events/hour that were never bugs: deleted worktrees, home-directories-registered-as-repos, vanished files — all thrown as generic Errors, escaping tRPC as INTERNAL_SERVER_ERROR, and reported. The top issue alone accumulated 359k events, and it was hiding a real product bug: the changes pane polls a permanently-gone worktree every 2.5s forever, spawning doomed git processes. An earlier attempt to fix this with name/errno allowlists in the Sentry middleware was rejected as classification-at-a-distance.
The contract
- Expected domain states are typed non-500
TRPCErrors translated where context lives. Third-party/OS errors get translated once, at the adapter that calls them. - The Sentry middleware is dumb and loud:
INTERNAL_SERVER_ERROR⇒ report, zero allowlists. A 500 now means a missed translation at a throw site — fix the router, never add a filter. - Degraded is never silent: the renderer shows the state and pollers back off.
What changed
Desktop main
- Adapters: simple-git construct failures,
getStatusNoLockfailures (maxBuffer/permissions/timeouts), and git worker timeouts becomeGitEnvironmentError(name-checked across the worker boundary);ensureWithinRootthrowsWorkspaceFsPathErrorlike its sibling guards. path-validation.tsthrows properly-codedTRPCErrors directly (UNREGISTERED_WORKTREE→404 etc.) — kills the deleted-workspace 500s at all ~33 call sites.changes.getStatus/getBranchespre-check worktree existence (pathExistsCached) before spawning git tasks — no more doomed git spawns — and translateNotGitRepoError/GitEnvironmentErrorwith causes.- Filesystem routers wrap service calls with an errno→TRPCError mapping (
ENOENT→404,EISDIR→400,EACCES→403,ENOSPC→412; messages verbatim). - Bare-throw sweep: Project/Workspace-not-found families →
NOT_FOUND; git lock contention, branch-already-checked-out, gh-not-installed/authed →PRECONDITION_FAILED; input validation →BAD_REQUEST; ui-state ENOSPC + browser-historySQLITE_FULLtyped. Catch-all "unknown failure" wrappers deliberately stay 500. - New
errorFormatterserializes plain-object{kind: ...}causes to the renderer (host-service pattern; verified the cause survives tRPC'sUnknownCauseErrorwrapping).
Renderer
useGitChangesStatussurfaceserror/errorCause; polling backs off to 30s on deterministic codes (400/403/404/412) and 10s on transient failures —refetchOnWindowFocusstill gives instant recovery. Changes pane renders "Workspace folder no longer exists on disk" / "not a git repository" / "Git can't read this workspace" instead of a catch-all.useFileContentbranches on theFS_ERRNOcause instead ofmessage.includes("EISDIR").- Renderer Sentry drops
TRPCClientErrorevents — the main-process middleware is the reporting source of truth.
Host-service (parity — previously reported nothing)
- Same dumb Sentry middleware under both procedure chains;
unhandledRejectionnow captured; errno translation in its filesystem router; typedWorkspaceNotFoundError/ProjectNotFoundErrorreplace string-prefix matching.
Verification
bun run lintclean; typecheck clean (desktop, host-service, workspace-fs).- Tests: 288 desktop (incl. new backoff matrix in
useGitChangesStatus.test.ts), 321 host-service, 58 workspace-fs — all pass. - Cause-serialization contract verified against tRPC's cause-wrapping behavior.
After ship (ops)
Takes effect as the fleet auto-updates to the next desktop release. Watch the desktop Sentry project: getStatus/getBranches clusters should go to ~0; host-service will report real 500s for the first time (expect a week-one triage wave). Any 500 carrying NotGitRepoError/GitEnvironmentError/WorkspaceFsPathError = missed translation arm to fix at the source.
https://claude.ai/code/session_012u6VZtfQgoTh8qS4NqCb7e
Summary by cubic
Translate expected desktop and host-service errors at throw sites into typed non-500 TRPCErrors with machine-readable causes, and keep the Sentry boundary “dumb” so only real 500s are reported. This cuts noisy events, stops endless git spawns on missing worktrees, and shows clear UI with smarter polling backoff.
-
Bug Fixes
- Git: pre-check worktree existence in
status/branches(and nowgetCommitFiles) and mapNotGitRepoError/GitEnvironmentErrorto 400/412; worker now translates raw simple-git “not a git repository” intoNotGitRepoErrorbefore crossing the boundary.worktreeExistsignores gitprunableentries;getStatusNoLockclassifies exec/timeout/maxBuffer as environment while porcelain parse failures surface as true 500s. - Filesystem/path/storage: map
ENOENT/EISDIR/ENOTDIR/EACCES/EPERM/ENOSPCand path-guard failures to non-500s withFS_ERRNO/PATH_VALIDATIONcauses; browser historySQLITE_FULLand UI-state ENOSPC/EACCES/EPERM return typed errors. - Host-service: workspace teardown-script failures return 412 with a structured cause;
unhandledRejectionis captured; Sentry middleware reports only 500s. - UI: Changes pane shows “folder missing / not a git repo / Git can’t read” and backs off polling to 30s on deterministic errors; file viewer branches on
FS_ERRNO; renderer Sentry drops duplicateTRPCClientErrors.
- Git: pre-check worktree existence in
-
Refactors
- All error translation lives in procedure bodies; utils throw domain errors only, and git-worker errors are rehydrated for
instanceofchecks. Added anerrorFormatterto serialize kind-discriminated causes to the renderer.
- All error translation lives in procedure bodies; utils throw domain errors only, and git-worker errors are rehydrated for
Summary by CodeRabbit
-
Bug Fixes
- Improved handling for missing workspaces, projects, worktrees, repositories, invalid paths, Git configuration issues, and filesystem failures.
- Storage-full, permission, unavailable-resource, and workspace cleanup failures now provide clearer actionable feedback.
- Git changes views distinguish unavailable states and display more relevant guidance.
- File viewing more reliably identifies directory-access errors.
-
Performance
- Git status polling backs off during persistent failures while continuing to retry transient issues.
-
Monitoring
- Improved reporting of unexpected service and Git failures while filtering handled client errors.