tinyhumansai/openhuman · error · Error

timed out waiting for core at ${coreUrl} ${stderrFn()}

Error message

timed out waiting for core at ${coreUrl}
${stderrFn()}

What it means

waitForCore() gives the spawned core 180 seconds to answer its first core.ping; if the deadline passes with the child still alive but silent, this error fires with the stderr tail. Unlike error 227 (child died), here the child runs but never serves RPC on the expected URL — overwhelmingly a cold-build problem: `cargo run` must compile the whole Rust core before the process even starts listening.

Source

Thrown at scripts/debug/goals-live.mjs:401

    });
  }
  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 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([
    once(child, "exit").then(() => true),
    new Promise((r) => setTimeout(() => r(false), 5000)),
  ]);
  if (exited) return;
  child.kill("SIGKILL");
  await Promise.race([once(child, "exit"), new Promise((r) => setTimeout(r, 2000))]);
}

// ── cases ───────────────────────────────────────────────────────────────────

function call(opts, method, params = {}) {
  return rpc(opts.coreUrl, opts.token, method, params, opts.rpcTimeoutMs);

View on GitHub (pinned to a221052e0d)

Solutions

  1. Prebuild once, then rerun: `cargo build --manifest-path Cargo.toml --bin openhuman-core` (subsequent spawns start in seconds)
  2. Rerun with --verbose to watch compile progress and confirm it is just slow
  3. Ensure no proxy intercepts loopback: `NO_PROXY=127.0.0.1` env
  4. Avoid competing cargo processes (release build, rust-analyzer full index) while spawning
  5. On persistently slow machines, build separately and run the audit against the pre-started binary without --spawn-core

Example fix

# before: first run, cold target/
node scripts/debug/goals-live.mjs --spawn-core
# Error: timed out waiting for core at http://127.0.0.1:XXXX/rpc

# after: prebuild, then spawn (reuses compiled binary)
cargo build --bin openhuman-core && node scripts/debug/goals-live.mjs --spawn-core
Defensive patterns

Strategy: fallback

Validate before calling

// warm the binary before running the script: guarantees the 180s boot window is enough
import { spawnSync } from "node:child_process";
const built = spawnSync("cargo", ["build", "--quiet", "--bin", "openhuman-core"], {
  cwd: repoRoot, stdio: "inherit",
});
if (built.status !== 0) { console.error("core failed to build"); process.exit(built.status ?? 1); }

Try / catch

try {
  await waitForCore(coreUrl, token, child, stderrFn);
} catch (err) {
  if (/timed out waiting for core/.test(err.message)) {
    // fall back: kill the child, prebuild, retry once
    await stopChild(child);
    spawnSync("cargo", ["build", "--quiet", "--bin", "openhuman-core"], { cwd: repoRoot, stdio: "inherit" });
    return await startCore(opts); // second attempt starts in seconds
  }
  throw err;
}

Prevention

When it happens

Trigger: First-ever (or after-clean) invocation: cargo compiles the core for >3 minutes while the script polls; incremental build after touching many crates; the child listens on a different port/path than opts.coreUrl (port parsing from the URL, proxy env vars redirecting 127.0.0.1); machine heavily loaded so compile+boot exceeds 180 s.

Common situations: Fresh clone running `pnpm debug goals-live -- --spawn-core` before any cargo build; CI runner or container with cold target/ cache; concurrently running another cargo build (lock contention); HTTPS_PROXY env capturing loopback fetches so ping never lands.

Understand the failure class

Related errors


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