{"record":{"id":"6c20fd0d45712c6b","repo":"paperclipai/paperclip","slug":"another-restart-for-instance-instanceid-is-stil","errorCode":null,"errorMessage":"Another restart for instance ${instanceId} is still running. If no restart process is active, remove the stale lock at ${lockPath} and retry.","messagePattern":"Another restart for instance (.+?) is still running\\. If no restart process is active, remove the stale lock at (.+?) and retry\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/src/commands/service.ts","lineNumber":97,"sourceCode":"      await fs.writeFile(lockPath, `${token}\\n`, { encoding: \"utf8\", mode: 0o600, flag: \"wx\" });\n      break;\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n      try {\n        const existingToken = (await fs.readFile(lockPath, \"utf8\")).trim();\n        const ownerPid = Number.parseInt(existingToken.split(\":\", 1)[0] ?? \"\", 10);\n        if (Number.isInteger(ownerPid) && ownerPid > 0 && !isProcessAlive(ownerPid)) {\n          if ((await fs.readFile(lockPath, \"utf8\")).trim() === existingToken) {\n            await fs.rm(lockPath, { force: true });\n            continue;\n          }\n        }\n      } catch (readError) {\n        if ((readError as NodeJS.ErrnoException).code === \"ENOENT\") continue;\n        throw readError;\n      }\n      if (Date.now() >= deadline) {\n        throw new Error(\n          `Another restart for instance ${instanceId} is still running. ` +\n          `If no restart process is active, remove the stale lock at ${lockPath} and retry.`,\n        );\n      }\n      await new Promise((resolve) => setTimeout(resolve, pollMs));\n    }\n  }\n\n  try {\n    return await callback();\n  } finally {\n    try {\n      if ((await fs.readFile(lockPath, \"utf8\")).trim() === token) {\n        await fs.rm(lockPath, { force: true });\n      }\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n    }","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/commands/service.ts#L79-L115","documentation":"Thrown by withHotRestartLock() when it cannot acquire the `hot-restart.lock` file within the 120s deadline. The lock is held by another restart (pid alive) or is stale but the pid-alive check could not clear it. The message tells the operator the lock path so they can intervene.","triggerScenarios":"Two concurrent `service restart` calls for the same instance, or a previous restart process is still alive, or a stale lock whose owner pid still appears alive (zombie/reused pid). The acquire loop fails `O_EXCL` write for >120s.","commonSituations":"Automation firing overlapping restarts; a crashed restart that left a lock whose pid was reused by an unrelated process; a long-running drain (`--wait`) exceeding the lock deadline.","solutions":["Confirm no restart is actually running: `ps aux | grep paperclip` and check the pid in the lock file.","If none is active, remove the stale lock: `rm <lockPath>` (path is in the error message), then retry.","Serialize restarts in automation with your own mutex so they never overlap.","If using `--wait` for drain, allow more time or drain manually before restart."],"exampleFix":"# before: overlapping restarts error\npaperclipai service restart\n# after: clear stale lock and serialize\nrm \"$HOME/.paperclip/<instance>/hot-restart.lock\"\npaperclipai service restart","handlingStrategy":"try-catch","validationCode":"import fs from 'node:fs';\nfunction lockStaleOrHeld(lockPath: string): boolean {\n  if (!fs.existsSync(lockPath)) return false;\n  const pid = Number(fs.readFileSync(lockPath, 'utf8').split(':')[0]);\n  try { process.kill(pid, 0); return true; } catch { return false; /* stale */ }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await withHotRestartLock(instanceId, () => doRestart());\n} catch (err) {\n  if (/stale lock/.test(String(err))) {\n    await fs.promises.rm(lockPath, {force: true});\n    // retry once\n  } else throw err;\n}","preventionTips":["Serialize restart calls in automation with your own lock/mutex.","After a crashed restart, clean the lock file before the next run."],"tags":["service","lock","concurrency","restart","stale-state"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}