heygen-com/hyperframes · critical · Error
background preview child did not report a PID
Error message
background preview child did not report a PID
What it means
Thrown by startBackgroundPreview after spawn() returns a child whose .pid is falsy. Node sets child.pid synchronously when the OS forks/execs the process; a missing pid means the process was never actually created (e.g. the executable path does not exist or the spawn failed at the OS level before a pid could be assigned).
Source
Thrown at packages/cli/src/commands/previewLifecycle.ts:152
const logPath = previewLogPath(projectDir, stateHome);
mkdirSync(dirname(logPath), { recursive: true });
const logFd = openSync(logPath, "a", 0o600);
const spawn = dependencies.spawn ?? (nodeSpawn as unknown as SpawnPreview);
let child: SpawnResult;
try {
child = spawn(
dependencies.execPath ?? process.execPath,
buildBackgroundPreviewArgs(dependencies.argv ?? process.argv.slice(1)),
{
detached: true,
stdio: ["ignore", logFd, logFd],
env: process.env,
},
);
} finally {
closeSync(logFd);
}
if (!child.pid) throw new Error("background preview child did not report a PID");
child.unref();
return { pid: child.pid, logPath };
}
function startedServer(
servers: ActiveServer[],
projectDir: string,
existing: ActiveServer | null,
forceNew: boolean,
browserGpuMode?: BrowserGpuMode,
): ActiveServer | null {
const candidates =
forceNew && existing ? servers.filter((server) => server.port !== existing.port) : servers;
return matchingServer(candidates, projectDir, browserGpuMode);
}
export function buildBackgroundPreviewArgs(argv: string[]): string[] {
const filtered = argv.filter(View on GitHub (pinned to c2996c8626)
Solutions
- Verify the Node binary is executable: `node -v` and `which node`
- Check process limits with `ulimit -u` and raise if at ceiling
- If injecting dependencies.execPath in tests/host code, ensure it resolves to a real executable
Defensive patterns
Strategy: retry
Validate before calling
import { existsSync } from "node:fs";
function nodeExecutableOk(p: string): boolean {
try { return existsSync(p) && (p === process.execPath); } catch { return false; }
} Try / catch
try {
await startBackgroundPreview(...);
} catch (e) {
if (String(e.message).includes("did not report a PID")) {
// verify node binary + raise process limits, then retry once
}
throw e;
} Prevention
- Confirm `node -v` works in the exact environment that spawns the preview
- Raise ulimit -u in containers/sandboxes before spawning detached children
- Avoid overriding process.execPath to an unverified path
When it happens
Trigger: dependencies.execPath / process.execPath points to a non-existent or non-executable Node binary; the host is at a process/resource limit so fork fails; a broken Node install invoked via a shim that cannot exec. The detached spawn with stdio routed to a log fd succeeds in returning a Child handle but with pid undefined.
Common situations: Running under a container/sandbox that restricts fork; NODE path overridden to a bad value; very low ulimit -u (max processes); a corrupted or relocated Node installation.
Related errors
- background preview did not become ready; see ${logPath}
- background preview did not stop for ${resolve(projectDir)}
- --context-fields cannot be empty
- Unknown context field${invalid.length === 1 ? "" : "s"}: ${i
- No free port found in [${startPort}, ${startPort + 9}]
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/6cd00be63f69c770.
Report an issue: GitHub.