Skip to content

fix(server): use custom codex binary path in provider health checks#793

Open
binbandit wants to merge 5 commits intopingdotgg:mainfrom
binbandit:fix/provider-health-custom-binary-path
Open

fix(server): use custom codex binary path in provider health checks#793
binbandit wants to merge 5 commits intopingdotgg:mainfrom
binbandit:fix/provider-health-custom-binary-path

Conversation

@binbandit
Copy link
Contributor

@binbandit binbandit commented Mar 10, 2026

Summary

Fixes #630 — the persistent "codex not found" error banner that appeared even when Codex sessions worked correctly with a custom binary path configured in Settings.

Root Cause

Three issues conspired to produce this bug:

  1. ProviderHealth.tsrunCodexCommand() hardcoded "codex" as the binary name. The health check always spawned the bare codex PATH lookup, ignoring the user's custom binary path from Settings.

  2. No recheck mechanism — The health check ran once at server boot via a forked fiber. There was no way to re-run it when the user changed the binary path in Settings afterward.

  3. __root.tsx dedup bug — The onServerConfigUpdated dedup signature only compared payload.issues (keybinding issues), not payload.providers. So even if health check results changed, the config update push was silently dropped as a "duplicate" — the UI never learned the status improved.

Changes

Server (apps/server)

  • ProviderHealth.ts: runCodexCommand() and checkCodexProviderStatus() now accept an optional binaryPath parameter (defaults to "codex"). Error messages include the actual binary path in the label. isCommandMissingCause() simplified to generic ENOENT/not-found detection (no longer hardcodes "codex" in the match strings).

  • Services/ProviderHealth.ts: Added recheckStatuses(binaryPath?) method to the service interface.

  • ProviderHealth.ts (Layer): ProviderHealthLive captures ChildProcessSpawner at layer construction time, exposes recheckStatuses() which re-runs the full health check pipeline with the given binary path and updates the cached statuses.

  • wsServer.ts: New server.recheckProviderHealth RPC handler — re-runs the health check, updates the cached providers, broadcasts updated statuses to all connected clients, and returns the full server config.

Contracts (packages/contracts)

  • server.ts: Added RecheckProviderHealthInput schema ({ codexBinaryPath?: TrimmedNonEmptyString }).
  • ws.ts: Added serverRecheckProviderHealth method constant and tagged request body.
  • ipc.ts: Added recheckProviderHealth to the NativeApi.server interface.

Web (apps/web)

  • wsNativeApi.ts: Wired recheckProviderHealth through the WS transport.
  • _chat.settings.tsx: Added a debounced (600ms) useEffect that triggers server.recheckProviderHealth whenever codexBinaryPath changes in Settings. Skips the initial mount to avoid unnecessary checks.
  • __root.tsx: Fixed the config update dedup signature to include providers, so push messages with updated health results are no longer silently dropped.

Tests

  • ProviderHealth.test.ts: Updated all 6 effect tests to call checkCodexProviderStatus() as a function instead of yielding the raw Effect constant. All 9 tests pass.
  • wsServer.test.ts: Updated the mock ProviderHealthShape to include recheckStatuses. All 36 tests pass.

Validation

  • bun lint — 0 errors
  • bun typecheck — passes for @t3tools/contracts, t3 (server), and @t3tools/web (only pre-existing unrelated @dnd-kit type errors in Sidebar.tsx)
  • All 49 contracts tests pass
  • All 76 server tests pass (ProviderHealth + wsServer + codexAppServerManager)

Note

Add server.recheckProviderHealth RPC to run health checks with a custom Codex binary path

  • Converts checkCodexProviderStatus from a static Effect value to a function accepting an optional binaryPath, allowing health checks to target a custom Codex binary.
  • Adds a recheckStatuses method to ProviderHealthShape and a new server.recheckProviderHealth WebSocket RPC method that accepts an optional codexBinaryPath, re-runs health checks, and broadcasts updated server config to all clients.
  • In the settings UI, changing the Codex binary path triggers a debounced (600ms) health recheck via React Query, updating the provider status cache.
  • Adds path validation via SAFE_BINARY_PATH_RE and quotes Windows paths with shell: true to handle spaces safely.
  • Fixes a bug in the serverConfigUpdated event handler where provider status changes were ignored if issues were unchanged.

Macroscope summarized 46ebfdc.

@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 2026

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

Run ID: 3751181a-14a8-4184-866d-da873da343f3

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
  • Post copyable unit tests in a comment

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.

@github-actions github-actions bot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Mar 10, 2026
@binbandit binbandit force-pushed the fix/provider-health-custom-binary-path branch from 123c7ad to a30cb08 Compare March 10, 2026 09:34
The provider health check always spawned the bare 'codex' command,
ignoring the user's custom binary path from Settings. This caused a
persistent 'codex not found' error banner even when sessions worked
correctly with the configured path.

Three root causes are addressed:

1. checkCodexProviderStatus and runCodexCommand now accept an optional
   binaryPath parameter instead of hardcoding 'codex'.

2. ProviderHealth service exposes a recheckStatuses method, wired
   through a new server.recheckProviderHealth WS RPC, so the web
   client can trigger a re-check when the binary path setting changes.

3. The __root.tsx config-update dedup signature now includes provider
   statuses, so push messages with updated health results are no
   longer silently dropped.

Closes pingdotgg#630
…d stale state

- Validate binaryPath against a safe-character allowlist and double-quote
  it on Windows to prevent command injection via shell metacharacters and
  handle paths with spaces (e.g. C:\Program Files\...).
- Read getStatuses from statusesRef instead of permanently returning the
  initial fiber result, so callers see updated data after recheckStatuses.
- Load keybindings config state before broadcasting serverConfigUpdated
  so the push payload contains actual issues instead of an empty array.
After rebasing onto main, checkCodexProviderStatus now depends on
FileSystem and Path (for hasCustomModelProvider config detection).
The runCheck helper in ProviderHealthLive must provide these services
alongside ChildProcessSpawner.
@binbandit binbandit force-pushed the fix/provider-health-custom-binary-path branch from abbb6ff to d499f5d Compare March 10, 2026 21:07
Replace manual useEffect/useRef/setTimeout debounce with
useDebouncedValue from @tanstack/react-pacer and a useMutation
backed by a serverRecheckProviderHealthMutationOptions factory,
aligning with the established React Query patterns in the codebase.
@binbandit
Copy link
Contributor Author

@juliusmarminge Good to go

…eMutation

The provider health recheck is semantically a query — given a binary
path, derive the health status. Model it as a useQuery keyed on the
debounced path so React Query handles retries, deduplication, and
cache lifecycle automatically, eliminating the need for manual
useEffect/useRef orchestration.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

'codex' not found error but it actually works

2 participants