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

  1. Read the stderr tail in the error message — it names the real cause (compile error, 'address already in use', panic backtrace)
  2. Free the port: kill the stale core (lsof -ti :7788 | xargs kill) or pass --core-url with a fresh port
  3. 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)
  4. 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

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


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/09dd1acbf92cd8f7. Report an issue: GitHub.