{"record":{"id":"579191e554e4f747","repo":"paperclipai/paperclip","slug":"failed-to-start-worktree-port-reservation-lock-hea","errorCode":null,"errorMessage":"Failed to start worktree port reservation lock heartbeat at ${lockPath}","messagePattern":"Failed to start worktree port reservation lock heartbeat at (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/shared/src/worktree-port-registry.ts","lineNumber":280,"sourceCode":"  const worker = new Worker(REGISTRY_LOCK_HEARTBEAT_SOURCE, {\n    eval: true,\n    execArgv: [],\n    workerData: {\n      control: control.buffer,\n      heartbeatMs: WORKTREE_PORT_REGISTRY_LOCK_HEARTBEAT_MS,\n      lockPath,\n      ownerFiles: [\n        WORKTREE_PORT_REGISTRY_LOCK_OWNER_FILE,\n        WORKTREE_PORT_REGISTRY_LOCK_OWNER_BACKUP_FILE,\n      ],\n      probeTimeoutMs: WORKTREE_PORT_REGISTRY_LOCK_PROBE_TIMEOUT_MS,\n      token,\n    },\n  });\n  Atomics.wait(control, 0, 0, 2_000);\n  if (Atomics.load(control, 0) !== 1) {\n    void worker.terminate();\n    throw new Error(`Failed to start worktree port reservation lock heartbeat at ${lockPath}`);\n  }\n  const probePort = Atomics.load(control, 2);\n  if (probePort <= 0) {\n    void worker.terminate();\n    throw new Error(`Failed to start worktree port reservation lock probe at ${lockPath}`);\n  }\n  return { token, worker, control, probePort };\n}\n\nfunction stopRegistryLockHeartbeat(lease: RegistryLockLease): void {\n  Atomics.store(lease.control, 1, 1);\n  Atomics.notify(lease.control, 1);\n  lease.worker.postMessage(\"stop\");\n  if (Atomics.load(lease.control, 0) === 1) {\n    Atomics.wait(lease.control, 0, 1, 2_000);\n  }\n  void lease.worker.terminate();\n}","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/paperclipai/paperclip/blob/a7e689b3c35347b529cb9f54c9b9a8575a3dcab6/packages/shared/src/worktree-port-registry.ts#L262-L298","documentation":"Thrown by startRegistryLockHeartbeat in the worktree port registry when the heartbeat Worker thread fails to signal readiness within 2 seconds (control flag never reaches 1). The heartbeat worker refreshes the lock's owner files and answers liveness probes; without it the lock cannot be held safely, so acquisition aborts and the freshly created lock directory is removed.","triggerScenarios":"withWorktreePortRegistryLockSync spins up the eval-mode Worker; the worker throws during startup (bad embedded source, Node flags incompatibility), or the process/system is so loaded the thread cannot start and touch the SharedArrayBuffer within the 2s Atomics.wait budget.","commonSituations":"Heavily loaded CI machines or containers with CPU/thread limits (cgroup pids.max, low ulimit) preventing thread spawn; restrictive sandboxed runtimes where worker_threads spawning is disabled; Node versions or execArgv (e.g. --experimental flags, inspector) that break eval workers; transient fork/resource exhaustion (EMFILE, ENOMEM).","solutions":["Retry the worktree/port-registry operation once; transient thread-start starvation is the most common cause.","Check thread/resource limits in the environment (ulimit -u, cgroup pids limit, available memory) and raise them.","Verify the Node.js version supports worker_threads and that no NODE_OPTIONS/execArgv flags interfere with eval workers.","Reduce concurrent worktree operations hammering the registry at the same moment."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Before heavy fan-out, confirm worker threads can start in this environment:\nimport { isMainThread, Worker } from \"node:worker_threads\";\nfunction workersAvailable(): Promise<boolean> {\n  return new Promise((resolve) => {\n    try {\n      const w = new Worker(\"Atomics.store(new Int32Array(workerData.b),0,1)\", { eval: true, workerData: { b: new SharedArrayBuffer(4) } });\n      w.on(\"error\", () => resolve(false));\n      w.on(\"exit\", (c) => resolve(c === 0));\n    } catch {\n      resolve(false);\n    }\n  });\n}","typeGuard":null,"tryCatchPattern":"try {\n  return withWorktreePortRegistryLockSync(home, run);\n} catch (error) {\n  if (error instanceof Error && error.message.includes(\"heartbeat\")) {\n    return withWorktreePortRegistryLockSync(home, run); // one retry for thread-start starvation\n  }\n  throw error;\n}","preventionTips":["Keep concurrent worktree/port-registry operations modest on loaded CI machines.","Check ulimit -u / cgroup pids.max before fan-out.","Avoid exotic execArgv/NODE_OPTIONS that break eval-mode workers.","Monitor and free FDs/memory; resource exhaustion often shows up first as worker spawn failures."],"tags":["worktree","port-registry","file-lock","worker-threads","concurrency"],"backgroundTag":"worker-thread-startup-failure","analyzedSha":"a7e689b3c35347b529cb9f54c9b9a8575a3dcab6","analyzedAt":"2026-08-21T17:58:32.592Z","contentChangedAt":"2026-08-21T17:58:32.592Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}