QVAC-18515 fix[api]: catch bare-runtime spawn failure instead of crashing the host#2467
Open
simon-iribarren wants to merge 5 commits into
Open
Conversation
3 tasks
lauripiisang
reviewed
Jun 5, 2026
The Node worker spawns via `bare-runtime`, which loads its platform binary
with `require('bare-runtime-<platform>-<arch>')`. As a transitive optional
dependency this package (or its nested deps) is frequently not installed under
pnpm even on a supported host, so `spawn` throws a terse
`No binaries found for target '<platform>-<arch>'` that escapes the IPC
listen callback as an uncaught exception and crashes the host process.
- Declare the desktop `bare-runtime-<platform>-<arch>` packages as
optionalDependencies of `@qvac/sdk` and `@qvac/cli` so package managers
install and link the matching platform binary directly (mirrors the
esbuild/swc pattern).
- Catch the spawn failure in the Node RPC client and reject with a structured
`BareRuntimeBinaryNotFoundError` (exported for `instanceof`) that names the
platform and the remedy, instead of crashing with the raw message.
- Document the pnpm caveat and workaround in the CLI README.
Current pnpm installs and links bare-runtime's matching bare-runtime-<platform>-<arch> package (and its nested deps) on its own, even when bare-runtime is a transitive optional dependency, so declaring the platform packages directly on @qvac/sdk and @qvac/cli adds no resolution guarantee. The substantive fix for tetherto#1492 is the spawn error handling in node-rpc-client.ts, which turns the synchronous bare-runtime throw (previously an uncaught exception that crashed the host) into a catchable BareRuntimeBinaryNotFoundError.
Every init reject path (timeout, IPC server error, synchronous spawn throw, pre-handshake worker exit) repeated the same module-state reset, and only some also closed the IPC server and unlinked the socket. Extract resetModuleState() and teardownFailedInit() so all reject paths reset state and release the worker/server/socket consistently, removing the drift and the resource leaks on the paths that previously only nulled state.
b627945 to
37a51b6
Compare
lauripiisang
requested changes
Jun 9, 2026
lauripiisang
left a comment
Contributor
There was a problem hiding this comment.
could you write a test that checks this new behavior through RPC init via lying about the platform, e.g. something like
const ogPlatform = process.platform;
Object.defineProperty(process, 'platform', { value: 'commodore64' });
// do your test
finally {
Object.defineProperty(process, 'platform', { value: ogPlatform });
}
Contributor
Ah wait, NVM. It also allows us to pass the |
Contributor
Tier-based Approval Status |
arun-mani-j
approved these changes
Jun 9, 2026
opaninakuffo
approved these changes
Jun 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

🎯 What problem does this PR solve?
The install failure originally reported in #1492 (
No binaries found for target '<platform>-<arch>'under pnpm) is already fixed on the current toolchain — it was a pnpm bug fixed in pnpm 11.0.0 (see "Original issue: already fixed" below). What remains unaddressed is the failure mode: when the Bare runtime binary genuinely can't be spawned, the SDK crashes the host process instead of throwing a catchable error.bare-runtimeresolves its platform binary synchronously withrequire('bare-runtime-<platform>-<arch>'). When that package — or one of its nested deps — can't be loaded, thespawncall throws synchronously inside the IPClistencallback. Nothing catches it, so it escapes as an uncaught exception and kills the host process. The thrown message is also misleading: a missing nested dependency surfaces as the terse "No binaries found".📝 How does it solve it?
spawn("bare", …)inclient/rpc/node-rpc-client.tsin atry/catch. On failure it tears down the half-initialized RPC state, closes the IPC server, and rejects the init promise instead of letting the throw crash the process.No binaries foundthrow to a structured, exportedBareRuntimeBinaryNotFoundErrorthat names the platform/arch and tells the user how to recover (installbare-runtime-<platform>-<arch>directly, or install with npm/bun).This is platform-independent: any synchronous
spawnfailure now becomes a catchable error rather than a host crash.✅ Original issue: already fixed
The #1492 install failure does not reproduce on the current toolchain — it was a pnpm resolution bug fixed in pnpm 11.0.0, not a
bare-runtime/@qvacissue.The
bare-runtimeplatform package (e.g.bare-runtime-darwin-arm64) depends onrequire-asset, and older pnpm doesn't linkrequire-assetinto the virtual store (node_modules/.pnpm/node_modules/require-asset), sorequire('bare-runtime-<platform>-<arch>')fails and surfaces as the misleading "No binaries found". Reproduced on macOS (arm64) installing the originally-reportedbare-runtime@1.28.4and resolving the binary the way the SDK does:No binaries found for target '<platform>-<arch>'barebinaryThe
bare-runtimeversion isn't the factor (even1.28.4resolves fine on pnpm 11). An earlier revision of this PR declared thebare-runtime-<platform>-<arch>packages asoptionalDependenciesof@qvac/sdk/@qvac/cli; since current pnpm already resolves the binary, those added no guarantee and were dropped to keep the change minimal.🧪 How was it tested?
bun install+tsc --noEmit,eslint --max-warnings=0, andprettier --checkon the changed files — all pass.No binaries found) and confirmed the new path rejects withBareRuntimeBinaryNotFoundErrorinstead of crashing the process.bare-runtime@1.28.4: fails on pnpm 8/9/10, resolves on pnpm 11 (see table above) — confirming the install issue is a pnpm bug already fixed upstream, hence the droppedoptionalDependencies.🔌 API Changes
New exported error class
BareRuntimeBinaryNotFoundError(non-breaking addition). Thrown during worker init when the platform's Bare runtime binary cannot be loaded.Closes #1492