Skip to content

feat(app): warn on Work when a sandbox fails to start - #262

Merged
quickbeard merged 1 commit into
mainfrom
warn-failed-sandbox
Aug 18, 2026
Merged

quickbeard merged 1 commit into
mainfrom
warn-failed-sandbox

Conversation

@quickbeard

Copy link
Copy Markdown
Owner

What

A sandbox whose boot failed showed the Work sidebar's wait message — "Your sandbox is not running yet. It appears here once it is ready." — a promise that was never going to be kept. The only way to learn something went wrong was to go looking in Settings → Servers.

The Work empty state now says the sandbox failed to start, shows the runtime's failure message (e.g. sandbox server did not become healthy within 30000ms), and offers a Try again button that starts it in place — the same action as Settings → Servers → Start, with the same error toast.

How

  • The message decision moves out of WorkspaceEmpty into the pure workspaceEmptyState in packages/app/src/workspace/side.ts (the testable home for Work-side decisions, beside leavesWorkEmpty). Precedence: a sandbox still coming up wins — a starting runtime, or any create/reset job, whose runtime reads "stopped" while it runs — because one sandbox on its way keeps the wait message true; only then is a failed sandbox called out; a side whose sandboxes are all deliberately stopped is the fallback. The old code keyed "stopped" off config.stopped, which is why a failed boot (flag unset) fell into the wait branch.
  • New i18n keys workspace.empty.failed / workspace.empty.failed.retry in en + es.
  • DIVERGENCES.md: the Code/Work workspace split row's i18n key list updated; a stale duplicate of that same row (predating empty.stopped) removed.
  • CHANGELOG.md: entry under Unreleased → Sandbox.

Why it matters

Observed in the wild: a bwrap sandbox boot timed out once at the 30s health gate (the guest server was up ~2s after spawn but never answered /global/health; 7 standalone replays of the identical create/reset + boot sequence were healthy in 1.7–3.7s, so it was transient host contention). A plain retry would have succeeded — but the sidebar's wait message hid that a retry was even needed.

Testing

  • 4 new cases in packages/app/test-browser/workspace-side.test.ts covering none/coming-up/failed/stopped precedence, including "a failure beside a starting sandbox does not interrupt the wait" and "a reset job's stopped runtime still reads as coming up".
  • bun run test:browser (101 tests) and bun typecheck pass from packages/app.

🤖 Generated with Claude Code

The Work empty state keyed "stopped" off config.stopped, so a sandbox
whose boot failed fell into the "not running yet, appears once ready"
wait message and the user was left waiting on a boot that already gave
up; the failure was only visible in Settings -> Servers. The message
decision moves to the pure workspaceEmptyState in workspace/side.ts:
a sandbox still coming up (starting runtime, or a create/reset job,
whose runtime reads "stopped" while it runs) keeps the wait message,
then a failed sandbox is called out with its runtime message and a
Try again button that starts it in place, and all-stopped stays the
fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@quickbeard
quickbeard merged commit 423ed99 into main Aug 18, 2026
0 of 5 checks passed
@quickbeard
quickbeard deleted the warn-failed-sandbox branch August 18, 2026 05:10
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