Skip to content

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

Closed
binbandit wants to merge 7 commits into
pingdotgg:mainfrom
binbandit:fix/provider-health-custom-binary-path
Closed

binbandit wants to merge 7 commits into
pingdotgg:mainfrom
binbandit:fix/provider-health-custom-binary-path

Conversation

@binbandit

@binbandit binbandit commented Mar 10, 2026 •

Copy link
Copy Markdown
Contributor

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.ts — runCodexCommand() 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 recheckProviderHealth WebSocket method to run health checks with a custom Codex binary path

  • checkCodexProviderStatus is refactored from a static Effect value into a function accepting an optional binaryPath (default 'codex'), which is validated against a safe-path regex before spawning a process.
  • A new recheckStatuses(binaryPath?) method is added to the ProviderHealth service and layer, storing results in a Ref so they can be refreshed on demand.
  • The WebSocket API gains a server.recheckProviderHealth method (ws.ts) that triggers a recheck and pushes an updated serverConfigUpdated event to all clients.
  • The settings page (_chat.settings.tsx) debounces (600ms) changes to the Codex binary path field and fires a recheck query, updating provider statuses in the UI automatically.
  • Duplicate serverConfigUpdated payloads with identical issues and providers are deduplicated in the event router to avoid redundant query invalidations and toasts.

Macroscope summarized cda49e0.

@coderabbitai

coderabbitai Bot commented Mar 10, 2026 •

Copy link
Copy Markdown
Contributor

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: 5721f0e3-2ba3-4ce9-b4e6-b31fccc7fb11

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
📝 Coding Plan
  • Generate coding plan for human review comments

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
Comment thread apps/server/src/provider/Layers/ProviderHealth.ts Outdated
Comment thread apps/server/src/provider/Layers/ProviderHealth.ts
Comment thread apps/web/src/routes/_chat.settings.tsx Outdated
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
Copy Markdown
Contributor Author

@juliusmarminge Good to go

Comment thread apps/web/src/routes/_chat.settings.tsx Outdated
…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.
@github-actions github-actions Bot added the size:L 100-499 changed lines (additions + deletions). label Mar 20, 2026
@maria-rcks maria-rcks closed this Apr 25, 2026
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: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

3 participants