{"record":{"id":"bf34e5c238ead076","repo":"heygen-com/hyperframes","slug":"background-preview-did-not-stop-for-resolve-proj","errorCode":null,"errorMessage":"background preview did not stop for ${resolve(projectDir)}","messagePattern":"background preview did not stop for (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/previewLifecycle.ts","lineNumber":280,"sourceCode":"  const server = matchingServer(await scan(scanStart), projectDir);\n  // A saved PID can be reused after a crashed preview, so only trust it while\n  // a currently reachable server proves this exact project is still running.\n  const pid = Number(server ? (server.pid ?? saved?.pid) : undefined);\n  if (!Number.isInteger(pid) || pid <= 0) {\n    removePreviewSession(projectDir, stateHome);\n    return false;\n  }\n\n  (dependencies.kill ?? stopProcess)(pid);\n  const sleep = dependencies.sleep ?? delay;\n  for (let attempt = 0; attempt < 25; attempt++) {\n    if (!matchingServer(await scan(scanStart), projectDir)) {\n      removePreviewSession(projectDir, stateHome);\n      return true;\n    }\n    await sleep(100);\n  }\n  throw new Error(`background preview did not stop for ${resolve(projectDir)}`);\n}\n","sourceCodeStart":262,"sourceCodeEnd":282,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/previewLifecycle.ts#L262-L282","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await stopBackgroundPreview(projectDir, startPort);\n} catch (e) {\n  if (e.message.includes(\"did not stop\")) {\n    // fall back to a direct port-holder kill, then re-scan\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["preview","process-management","shutdown","network"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}