Skip to content

fix(desktop): surface sidecar startup failures instead of hanging silently (#382) - #479

Open
lmanchu wants to merge 1 commit into
andrewyng:mainfrom
lmanchu:fix/sidecar-startup-fault-screen
Open

fix(desktop): surface sidecar startup failures instead of hanging silently (#382)#479
lmanchu wants to merge 1 commit into
andrewyng:mainfrom
lmanchu:fix/sidecar-startup-fault-screen

Conversation

@lmanchu

@lmanchu lmanchu commented Aug 9, 2026

Copy link
Copy Markdown

Summary

Fixes the "silent" half of #382: on the packaged desktop app, when the Python sidecar never comes up, the UI renders fully navigable while every backend call hangs forever — no error surfaced anywhere.

Root-cause chain (code-verified on main):

  • server_bin() (src-tauri/src/lib.rs) resolves through the sidecar candidates; when spawn() fails, the only signal is an eprintln! — invisible for a Finder-launched app. The shell then continues with no server.
  • Even when the spawn succeeds, nothing watches the child: if it exits during startup (bad interpreter, missing dylib, crashed bootloader…) or never binds its port, nothing notices.
  • The SPA's boot health polling (App.tsx) burns its ~20s of retries and then presents the normal UI as if everything were fine.

What changed

  • Shell (Rust): records sidecar startup state — "starting""listening" once the port accepts, or "spawn_failed" / "exited" (with the exit status) — and exposes it via a new get_server_status command. A short-lived watcher thread resolves the state and exits; steady-state cost is zero.
  • SPA: when boot health checks fail on desktop, it asks the shell. A dead sidecar fails fast (no 20-second wait) to a full-stop fault screen with the failure detail plus the server log and binary paths; a sidecar that never answers gets the same screen once retries exhaust. The browser build keeps today's behavior.
  • The fault screen deliberately outranks the folder gate — nothing behind the gate works without the backend.

This doesn't fix whatever kills a given machine's sidecar (likely several distinct causes behind #382), but it converts each of them from an indefinite silent hang into a visible, diagnosable stop — the log path shown is exactly where the answer lands.

For anyone hitting this today on current builds: ~/.config/coworker/logs/openworker-server.log already captures the sidecar's stdout/stderr and should say why yours died.

Validation

  • npx tsc --noEmit — clean
  • npx vitest run — 114 passed (3 new, ServerFault component)
  • npx playwright test e2e/server-fault.spec.ts e2e/boot.spec.ts e2e/error-retry.spec.ts e2e/smoke.spec.ts — 6 passed (1 new: dead sidecar → fault screen, and the folder gate must not appear)
  • cargo check in src-tauri — clean
  • No Python changes.

Screenshots

Broken (current main, simulated dead sidecar): the app renders a normal, fully navigable UI; every backend action hangs with no error:

before

Fixed — sidecar exited during startup:

after-exited

Fixed — sidecar alive but never answering (retries exhausted):

after-unresponsive

🤖 Generated with Claude Code

…ently

The packaged app rendered a fully navigable UI even when the Python
sidecar never came up (spawn failed, exited during startup, or never
bound its port) - every backend call then hung forever with no error
surfaced anywhere (andrewyng#382). The only signal was an eprintln to a stderr
nobody can see under a Finder launch.

The shell now records what happened to the sidecar ("starting" ->
"listening", or "spawn_failed"/"exited" with the exit detail) and
exposes it through a get_server_status command. When the SPA's boot
health polling fails it asks the shell: a dead sidecar fails fast to a
full-stop fault screen showing the server log and binary paths; an
unresponsive one gets the same screen once retries exhaust. Browser
builds keep the existing behavior.

🤖 Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant