sinelaw/fresh · error
editor.spawnHostProcess is not implemented (missing…
Error message
editor.spawnHostProcess is not implemented (missing _spawnHostProcessStart)
What it means
editor.spawnHostProcess is a JS shim that requires the Rust host binding editor._spawnHostProcessStart to exist; it forwards to a real ProcessHandle whose kill() calls _killHostProcess. When the binding is missing, the shim throws because host process spawning (and its kill support) cannot be implemented generically. The shim also deliberately only passes real strings so the Rust Opt<String> stays None for an omitted cwd instead of "", avoiding Command::current_dir("") ENOENT failures.
Solutions
- Ensure the runtime registers _spawnHostProcessStart (and _killHostProcess) — upgrade fresh-plugin-runtime or rebuild with host-spawn support enabled.
- Feature-detect editor._spawnHostProcessStart before calling spawnHostProcess and fall back to a supported API (e.g. editor.spawnProcess).
- Pass cwd as undefined rather than "" so the Rust Opt<String> stays None and avoids Command::current_dir("") ENOENT once the binding exists.
- If host process spawning is intentionally disabled on the target, restructure the plugin to request capabilities from the host instead.
Example fix
// before
const p = editor.spawnHostProcess("make", ["build"], "");
// after
if (typeof editor._spawnHostProcessStart !== "function") {
throw new Error("host process spawning unavailable");
}
const p = editor.spawnHostProcess("make", ["build"], undefined); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof editor._spawnHostProcessStart !== "function") {
throw new Error("host process spawning not supported in this runtime");
} Type guard
function supportsHostSpawn(editor) {
return typeof editor._spawnHostProcessStart === "function" &&
typeof editor.spawnHostProcess === "function";
} Try / catch
try {
handle = editor.spawnHostProcess(cmd, args, cwd);
} catch (e) {
if (String(e.message).includes("_spawnHostProcessStart")) {
// fall back to editor.spawnProcess or non-process approach
} else throw e;
} Prevention
- Feature-detect editor._spawnHostProcessStart before calling spawnHostProcess.
- Pass undefined (not "") for an omitted cwd so the Rust Opt<String> stays None and avoids ENOENT.
- Confirm host-process support is enabled in the backend build/sandbox policy.
- Prefer editor.spawnProcess with a documented fallback when host spawning is unavailable.
When it happens
Trigger: Calling editor.spawnHostProcess(cmd, args, cwd) when editor._spawnHostProcessStart is not a function — the quickjs_backend.rs runtime never installed the host-process binding (build without host-spawn support, older runtime, or a sandbox that excludes host process APIs).
Common situations: Plugins spawning host processes on a backend that lacks the _killHostProcess/_spawnHostProcessStart pair; runtime version drift between plugin API expectations and installed editor; restricted sandboxes where host process access is intentionally disabled.
Related errors
- editor.spawnProcess is not implemented (missing…
- TypeScript plugin thread creation failed
- openFileInSplit: split
- previewFileInSplit: split
- Failed to spawn shell
AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13).
Data as JSON: /api/errors/2485e09c9b5b351c.
Report an issue: GitHub.
Appendix: source
Thrown at crates/fresh-plugin-runtime/src/backend/quickjs_backend.rs:8657
}
return false;
},
then(onFulfilled, onRejected) {
return resultPromise.then(onFulfilled, onRejected);
},
catch(onRejected) {
return resultPromise.catch(onRejected);
}
};
};
// spawnHostProcess gets a bespoke wrapper (instead of
// `_wrapAsyncThenable`) because its `ProcessHandle`
// exposes a real `kill()` that forwards to
// `_killHostProcess`. Generic wrap has no hook for
// that.
editor.spawnHostProcess = function(command, args, cwd) {
if (typeof editor._spawnHostProcessStart !== 'function') {
throw new Error('editor.spawnHostProcess is not implemented (missing _spawnHostProcessStart)');
}
// Pass real strings only. Earlier revisions forwarded
// `""` for a missing cwd, which landed verbatim as
// `Command::current_dir("")` in the dispatcher —
// every host-spawn then failed with ENOENT. Use two
// arity forms so the Rust `Opt<String>` stays `None`
// instead of `Some("")`.
let callbackId;
if (typeof cwd === "string" && cwd.length > 0) {
callbackId = editor._spawnHostProcessStart(command, args || [], cwd);
} else {
callbackId = editor._spawnHostProcessStart(command, args || []);
}
const resultPromise = new Promise(function(resolve, reject) {
globalThis._pendingCallbacks.set(callbackId, { resolve: resolve, reject: reject });
});
return {
processId: callbackId,View on GitHub (pinned to 67894ca546)