heygen-com/hyperframes · error · Error
background preview did not stop for ${resolve(projectDir)}
Error message
background preview did not stop for ${resolve(projectDir)} What it means
Thrown by stopBackgroundPreview when the previously-spawned preview server is still reported by scanActiveServers after 25 polling attempts (100ms apart). The pid was signalled (dependencies.kill / stopProcess) but the server keeps answering, so the session can't be considered stopped.
Source
Thrown at packages/cli/src/commands/previewLifecycle.ts:280
const server = matchingServer(await scan(scanStart), projectDir);
// A saved PID can be reused after a crashed preview, so only trust it while
// a currently reachable server proves this exact project is still running.
const pid = Number(server ? (server.pid ?? saved?.pid) : undefined);
if (!Number.isInteger(pid) || pid <= 0) {
removePreviewSession(projectDir, stateHome);
return false;
}
(dependencies.kill ?? stopProcess)(pid);
const sleep = dependencies.sleep ?? delay;
for (let attempt = 0; attempt < 25; attempt++) {
if (!matchingServer(await scan(scanStart), projectDir)) {
removePreviewSession(projectDir, stateHome);
return true;
}
await sleep(100);
}
throw new Error(`background preview did not stop for ${resolve(projectDir)}`);
}
View on GitHub (pinned to c2996c8626)
Solutions
- Find and kill the holder of the port manually: `lsof -i :<port>` / `netstat` then kill
- Run `hyperframes preview --stop` again or use `--force`
- Check the saved session (readPreviewSession) for a stale pid and clear the state file
- Raise permissions / run as the same user that started the server
Defensive patterns
Strategy: try-catch
Try / catch
try {
await stopBackgroundPreview(projectDir, startPort);
} catch (e) {
if (e.message.includes("did not stop")) {
// fall back to a direct port-holder kill, then re-scan
}
throw e;
} Prevention
- Stop servers from the same user/session that started them
- Avoid running multiple preview servers on overlapping port ranges
- Clear stale session state when a pid is known to be dead
When it happens
Trigger: stopBackgroundPreview kills the pid then loops up to 25 times checking matchingServer; if it never disappears within ~2.5s the throw fires at previewLifecycle.ts:280.
Common situations: The pid belonged to a process that already exited and a different process reused the port; the kill signal is being ignored or the process is stuck in a non-interruptible state; a second preview server is also bound to the scanned port range; permissions prevent killing the owner.
Related errors
- background preview did not become ready; see ${logPath}
- background preview child did not report a PID
- No free port found in [${startPort}, ${startPort + 9}]
- [build-zip] npm install into staging failed (status ${result
- Model download failed: ${model}
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/bf34e5c238ead076.
Report an issue: GitHub.