{"record":{"id":"d65182da57f21355","repo":"paperclipai/paperclip","slug":"service-process-exited-after-losing-its-allocated","errorCode":null,"errorMessage":"service process exited after losing its allocated port","messagePattern":"service process exited after losing its allocated port","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/workspace-runtime.ts","lineNumber":4825,"sourceCode":"  child: ChildProcess;\n}) {\n  const deadline = Date.now() + resolveWorkspaceRuntimeReadinessTimeoutSec(input.service) * 1000;\n  while (Date.now() < deadline) {\n    if (input.child.exitCode !== null || input.child.signalCode !== null) {\n      throw new Error(\"service process exited before binding its allocated port\");\n    }\n\n    const ownerPid = await readLocalServicePortOwner(input.port);\n    if (ownerPid) {\n      const childPid = input.child.pid ?? null;\n      if (!childPid || !(await isLocalServiceProcessOwnedBy(ownerPid, childPid))) {\n        throw new RuntimeServicePortBindCollision(input.port);\n      }\n      // Require the same launched process group to retain ownership across a stability delay.\n      // Cwd matching alone is insufficient because sibling services can share a workspace.\n      await delay(250);\n      if (input.child.exitCode !== null || input.child.signalCode !== null) {\n        throw new Error(\"service process exited after losing its allocated port\");\n      }\n      const stableOwnerPid = await readLocalServicePortOwner(input.port);\n      if (!stableOwnerPid || !(await isLocalServiceProcessOwnedBy(stableOwnerPid, childPid))) {\n        throw new RuntimeServicePortBindCollision(input.port);\n      }\n      return;\n    }\n\n    // A present listener proves only that some listener appeared. If listener ownership cannot\n    // be attributed to this child after a stability delay, retry instead of accepting a sibling.\n    // The presence read never binds the port, so it cannot steal the port from the child.\n    if (await hasLoopbackPortListener(input.port)) {\n      await delay(250);\n      if (input.child.exitCode !== null || input.child.signalCode !== null) {\n        throw new Error(\"service process exited after losing its allocated port\");\n      }\n      const stableOwnerPid = await readLocalServicePortOwner(input.port);\n      const childPid = input.child.pid ?? null;","sourceCodeStart":4807,"sourceCodeEnd":4843,"githubUrl":"https://github.com/paperclipai/paperclip/blob/a7e689b3c35347b529cb9f54c9b9a8575a3dcab6/server/src/services/workspace-runtime.ts#L4807-L4843","documentation":"During the port-bind wait, a listener appeared on the allocated port but then the child process exited after losing ownership of it — the port ended up held by another process. Reported as a collision-style failure of the service start.","triggerScenarios":"Thrown at server/src/services/workspace-runtime.ts:4672 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Review the service logs for the crash after binding, fix the underlying error, and restart.","Ensure no other process stole the port while the service was running."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"a7e689b3c35347b529cb9f54c9b9a8575a3dcab6","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}