{"record":{"id":"09dd1acbf92cd8f7","repo":"tinyhumansai/openhuman","slug":"spawned-core-exited-with-child-exitcode-n-stde","errorCode":null,"errorMessage":"spawned core exited with ${child.exitCode}\\n${stderrFn()}","messagePattern":"spawned core exited with (.+?)\\\\n(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/debug/agent-prepare-context-audit.mjs","lineNumber":617,"sourceCode":"        : [\"ignore\", \"ignore\", \"pipe\"],\n    },\n  );\n  let stderr = \"\";\n  if (child.stderr) {\n    child.stderr.on(\"data\", (chunk) => {\n      stderr += chunk.toString();\n      if (stderr.length > 8000) stderr = stderr.slice(-8000);\n    });\n  }\n  await waitForCore(opts.coreUrl, token, child, () => stderr);\n  return { child, token };\n}\n\nasync function waitForCore(coreUrl, token, child, stderrFn) {\n  const deadline = Date.now() + 180_000;\n  while (Date.now() < deadline) {\n    if (child.exitCode !== null)\n      throw new Error(\n        `spawned core exited with ${child.exitCode}\\n${stderrFn()}`,\n      );\n    try {\n      await rpc(coreUrl, token, \"core.ping\", {}, 10_000);\n      return;\n    } catch {\n      await new Promise((r) => setTimeout(r, 750));\n    }\n  }\n  throw new Error(\n    `timed out waiting for spawned core at ${coreUrl}\\n${stderrFn()}`,\n  );\n}\n\nasync function stopChild(child) {\n  if (child.exitCode !== null || child.signalCode !== null) return;\n  child.kill(\"SIGTERM\");\n  const exited = await Promise.race([","sourceCodeStart":599,"sourceCodeEnd":635,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/scripts/debug/agent-prepare-context-audit.mjs#L599-L635","documentation":"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.","triggerScenarios":"--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.","commonSituations":"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.","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)\n","Unset conflicting env (OPENHUMAN_WORKSPACE unless explicitly wanted) so the core resolves the signed-in active user, per the comment in startCore()"],"exampleFix":"# before\n$ node scripts/debug/agent-prepare-context-audit.mjs --spawn-core\nError: spawned core exited with 101\nthread 'main' panicked ... Address already in use (os error 98)\n\n# after\n$ lsof -ti :7788 | xargs kill\n$ node scripts/debug/agent-prepare-context-audit.mjs --spawn-core","handlingStrategy":"try-catch","validationCode":"// Pre-flight: make sure the binary builds and the port is free BEFORE spawning\nimport { spawnSync } from \"node:child_process\";\nconst build = spawnSync(\"cargo\", [\"build\", \"--manifest-path\", \"Cargo.toml\", \"--bin\", \"openhuman-core\"], { stdio: \"inherit\" });\nif (build.status !== 0) process.exit(build.status ?? 1);\nconst port = new URL(coreUrl).port || \"7788\";\nconst probe = spawnSync(\"lsof\", [\"-ti\", `:${port}`], { encoding: \"utf8\" });\nif (probe.stdout.trim()) throw new Error(`port ${port} busy (pid ${probe.stdout.trim()}) — kill it or change --core-url`);","typeGuard":null,"tryCatchPattern":"try {\n  await waitForCore(coreUrl, token, child, () => stderr);\n} catch (e) {\n  if (/spawned core exited with (\\d+)/.test(e.message)) {\n    // stderr tail is embedded — surface it verbatim, it names the compile/bind/panic cause\n    console.error(e.message);\n    process.exit(child.exitCode ?? 1);\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["process","spawn","startup","build"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}