Skip to content

fix(app): stop a removed server's route from taking the renderer down - #244

Merged
quickbeard merged 1 commit into
mainfrom
fix/sandbox-route-crash
Aug 16, 2026
Merged

quickbeard merged 1 commit into
mainfrom
fix/sandbox-route-crash

Conversation

@quickbeard

Copy link
Copy Markdown
Owner

Deleting a sandbox while one of its sessions was open crashed the window to the fatal "Something went wrong" screen with Error: Invalid server route. And because the desktop restores the last active route on launch, every relaunch crashed again until the persisted URL happened to change.

Cause

requireServerKey throws when the route segment is missing or does not round-trip:

export function requireServerKey(segment: string | undefined) {
  const key = decode64(segment)
  if (!key || base64Encode(key) !== segment) throw new Error("Invalid server route")
  ...
}

Both route call sites ran it during render — one inside a createMemo, one as a JSX prop — so the throw escaped a reactive computation and took the whole renderer down.

And the param does go missing in ordinary use: removing a server navigates away (tabs.removeServer → navigate("/")), and the route's params clear before its subtree unmounts. That is exactly the delete-a-sandbox path.

Fix

serverKeyFromRoute is a non-throwing variant; requireServerKey is now defined in terms of it and kept for callers that want the throw. The two route components use the non-throwing one.

Rendering nothing turned out not to be enough on its own: a /server/… route that cannot mount its providers leaves the shell half-built and then fails further down in the command registry (reg.options is not a function, in a tight loop). So an unreadable key redirects home rather than sitting on a route that can never render.

Verified against the running app

I drove the real desktop app over the DevTools protocol rather than reasoning about it:

  • Before: booting on a route whose server key is unreadable → fatal error screen.
  • After: the "Invalid server route" throw is gone entirely.
  • The realistic case — a valid key for a server that no longer exists, which is what a deleted sandbox leaves behind — now recovers to a valid route with crashed: false and zero renderer errors.

Also in this PR: a lone sandbox job briefly announced itself as "Waiting for another sandbox…" before starting. The status now starts as running when nothing (that is not already superseded) is ahead of it in the queue, with a test pinning it.

Scope

This is an upstream bug of the same class as the project-avatar-state.ts guard already in DIVERGENCES.md — any removal, restart, or crash of a sidecar server drops its key while routes and tabs still point at it. A new divergence row records the guard and warns against "simplifying" the route back to requireServerKey.

Tests: packages/app 675 pass, packages/codev-sandbox 146 pass (1 new), packages/desktop 96 pass; bun typecheck clean in all three.

🤖 Generated with Claude Code

Deleting a sandbox while one of its sessions was open crashed the window to
the fatal error screen with "Invalid server route", and since the desktop
restores the last active route on launch, every relaunch crashed again until
the persisted URL happened to change.

requireServerKey throws on a segment that is missing or does not round-trip,
and both route call sites ran it during render, so the throw escaped from a
memo and killed the renderer. The param goes missing in ordinary use: removing
a server navigates away (tabs.removeServer -> navigate("/")) and the route's
params clear before its subtree unmounts.

The routes now read the key through a non-throwing serverKeyFromRoute.
Rendering nothing was not enough by itself — a /server/… route that cannot
mount its providers leaves the shell half-built and fails further down in the
command registry — so an unreadable key redirects home instead.

Verified against the running app: a route pointing at a deleted server now
recovers to a valid route with no renderer errors, where before it was fatal.

Also stops a lone job announcing itself as "waiting for another sandbox": the
status now starts as running when nothing (that is not already superseded) is
ahead of it in the queue.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@quickbeard
quickbeard force-pushed the fix/sandbox-route-crash branch from ff0bc89 to 4d4bd53 Compare August 16, 2026 05:15
@quickbeard
quickbeard merged commit 3f41136 into main Aug 16, 2026
0 of 5 checks passed
@quickbeard
quickbeard deleted the fix/sandbox-route-crash branch August 16, 2026 05:20
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