tinyhumansai/openhuman · error · Error
spawned core exited with ${child.exitCode}\n${stderrFn()}
Error message
spawned core exited with ${child.exitCode}\n${stderrFn()} What it means
waitForCore() in scripts/debug/agent-prepare-context-audit.mjs polls the spawned core (cargo run --bin openhuman-core, port derived from --core-url) every 750ms for up to 180s. If the child process exits at any point during the wait, it throws 'spawned core exited with <code>' together with the last 8000 characters of captured stderr — the actual reason the core died is in that stderr tail.
Source
Thrown at scripts/debug/agent-prepare-context-audit.mjs:617
: ["ignore", "ignore", "pipe"],
},
);
let stderr = "";
if (child.stderr) {
child.stderr.on("data", (chunk) => {
stderr += chunk.toString();
if (stderr.length > 8000) stderr = stderr.slice(-8000);
});
}
await waitForCore(opts.coreUrl, token, child, () => stderr);
return { child, token };
}
async function waitForCore(coreUrl, token, child, stderrFn) {
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
if (child.exitCode !== null)
throw new Error(
`spawned core exited with ${child.exitCode}\n${stderrFn()}`,
);
try {
await rpc(coreUrl, token, "core.ping", {}, 10_000);
return;
} catch {
await new Promise((r) => setTimeout(r, 750));
}
}
throw new Error(
`timed out waiting for spawned core at ${coreUrl}\n${stderrFn()}`,
);
}
async function stopChild(child) {
if (child.exitCode !== null || child.signalCode !== null) return;
child.kill("SIGTERM");
const exited = await Promise.race([View on GitHub (pinned to a221052e0d)
Solutions
- Read the stderr tail in the error message — it names the real cause (compile error, 'address already in use', panic backtrace)
- Free the port: kill the stale core (lsof -ti :7788 | xargs kill) or pass --core-url with a fresh port
- Pre-build so compile failures surface outside the 180s window: cargo build --manifest-path Cargo.toml --bin openhuman-core, then re-run with --spawn-core (cargo run reuses the warm target)
- Unset conflicting env (OPENHUMAN_WORKSPACE unless explicitly wanted) so the core resolves the signed-in active user, per the comment in startCore()
Example fix
# before $ node scripts/debug/agent-prepare-context-audit.mjs --spawn-core Error: spawned core exited with 101 thread 'main' panicked ... Address already in use (os error 98) # after $ lsof -ti :7788 | xargs kill $ node scripts/debug/agent-prepare-context-audit.mjs --spawn-core
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: make sure the binary builds and the port is free BEFORE spawning
import { spawnSync } from "node:child_process";
const build = spawnSync("cargo", ["build", "--manifest-path", "Cargo.toml", "--bin", "openhuman-core"], { stdio: "inherit" });
if (build.status !== 0) process.exit(build.status ?? 1);
const port = new URL(coreUrl).port || "7788";
const probe = spawnSync("lsof", ["-ti", `:${port}`], { encoding: "utf8" });
if (probe.stdout.trim()) throw new Error(`port ${port} busy (pid ${probe.stdout.trim()}) — kill it or change --core-url`); Try / catch
try {
await waitForCore(coreUrl, token, child, () => stderr);
} catch (e) {
if (/spawned core exited with (\d+)/.test(e.message)) {
// stderr tail is embedded — surface it verbatim, it names the compile/bind/panic cause
console.error(e.message);
process.exit(child.exitCode ?? 1);
}
throw e;
} Prevention
- Always pre-build (cargo build --bin openhuman-core) before --spawn-core so compile errors surface in your terminal, not inside a 180s wait
- Check the port before spawning — leftover cores from crashed runs are the most common bind failure
- Don't export OPENHUMAN_WORKSPACE unless you mean it: startCore() deliberately leaves it unset so the core resolves the signed-in active user
When it happens
Trigger: --spawn-core runs where the child dies during startup: the Rust build fails (cargo run compiles first — a compile error exits non-zero with the rustc error in stderr), the chosen port is already bound, the workspace/session state is invalid (e.g. explicitly set --workspace creating a nested config dir without a signed-in session), or the core panics on boot due to a bad config/env.
Common situations: Running --spawn-core on a dirty tree that doesn't compile; port 7788 (or the --core-url port) occupied by a leftover core from a previous crashed run (kill it: the error output names the bind failure); OPENHUMAN_WORKSPACE/OPENHUMAN_APP_ENV env vars inherited into the spawned core mismatching the active user, causing boot failure. The stderr tail is intentionally capped at 8000 chars so the beginning of long build errors may be truncated.
Related errors
- timed out waiting for spawned core at ${coreUrl}\n${stderrFn
- spawned core exited with ${child.exitCode} ${stderrFn()}
- Invalid ${paramName}: '${value}'. Must be a valid integer ID
- timed out waiting for core at ${coreUrl} ${stderrFn()}
- spawned core exited with ${child.exitCode} ${stderrFn()}
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/09dd1acbf92cd8f7.
Report an issue: GitHub.