#15345: fix(daemon): doctor --fix pollutes service PATH with dirs that don't exist (#15316)
gateway
stale
size: S
Cluster:
Node and macOS Enhancements
## Summary
`doctor --fix` writes nonexistent directories into the systemd unit's `Environment=PATH=...` line. On nvm setups without a `current` symlink, this includes `~/.nvm/current/bin` which doesn't exist — gateway starts fine (absolute node path in `ExecStart`), but spawned subprocesses can fail PATH resolution.
Closes #15316
lobster-biscuit
## Root Cause
`getMinimalServicePathParts` in `service-env.ts` collects candidate directories from `resolveLinuxUserBinDirs` (hardcoded paths like `${home}/.nvm/current/bin`) and dedupes them, but never checks whether they actually exist on disk. The full list gets written verbatim into the unit file.
## Changes
- Before: all candidate dirs written to PATH regardless of existence
- After: `fs.statSync` filters out dirs that don't exist before returning
The filter sits in `getMinimalServicePathParts`, so both the service generation path (`buildServiceEnvironment`) and the audit path (`auditGatewayServicePath`) stay consistent.
## Tests
- `service-env.test.ts` — added "excludes nonexistent directories from PATH (#15316)" test, fails before fix, passes after
- Updated all existing tests to mock `fs.statSync` (the new filter would otherwise drop test-only paths)
- All 116 daemon directory tests pass
- `pnpm build && pnpm check` pass
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR updates the daemon’s minimal PATH generation to filter out non-existent directories when composing systemd/launchd service environments, preventing `doctor --fix` from writing dead entries like `~/.nvm/current/bin`.
Core change is in `getMinimalServicePathParts`, which now `statSync`s each candidate dir and only keeps entries that exist and are directories. Tests in `service-env.test.ts` were updated to mock `fs.statSync` to keep them deterministic and to add coverage for excluding missing paths.
One follow-up needed: an existing audit test (`service-audit.test.ts`) constructs a minimal PATH without mocking the filesystem, so it becomes environment-dependent and may no longer assert inclusion of user bin roots (e.g. `PNPM_HOME`).
<h3>Confidence Score: 4/5</h3>
- This PR is largely safe to merge, with one test needing adjustment to remain deterministic.
- The production change is small and matches the stated root cause (filter nonexistent PATH entries). The main concern is that `service-audit.test.ts` now depends on the host filesystem due to the new filtering, reducing coverage and potentially causing CI variability.
- src/daemon/service-audit.test.ts
<sub>Last reviewed commit: 498edc2</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#12804: fix(daemon): use wrapper script for pnpm global installs in service...
by odinho · 2026-02-09
79.6%
#4709: fix(daemon): include user bin dirs in macOS LaunchAgent PATH
by ekson73 · 2026-01-30
77.7%
#21188: doctor: clean up legacy Linux gateway services
by Phineas1500 · 2026-02-19
77.3%
#15903: fix(doctor): stricter gateway service detection to prevent false po...
by Shuai-DaiDai · 2026-02-14
77.1%
#23666: fix(doctor): openclaw-browser.service falsely flagged as duplicate ...
by yinghaosang · 2026-02-22
76.7%
#18112: fix(daemon): gateway install on macOS ignores fnm/nvm node (#18090)
by yinghaosang · 2026-02-16
76.1%
#9154: fix(doctor): resolve symlinks before comparing state directories
by gavinbmoore · 2026-02-04
75.9%
#18939: fix: tighten permissions on cron/, browser/, settings/, logs/ in do...
by sriram369 · 2026-02-17
75.8%
#13084: fix(daemon): multi-layer defense against zombie gateway processes
by openperf · 2026-02-10
75.8%
#4897: fix: config logic issues (#4689, #4654)
by lailoo · 2026-01-30
75.6%