{"record":{"id":"c75098839732beb1","repo":"paperclipai/paperclip","slug":"another-managed-install-is-already-running-ownerl","errorCode":null,"errorMessage":"Another managed install is already running${ownerLabel}. If no install process is active, remove the stale lock at ${paths.lockPath} and retry.","messagePattern":"Another managed install is already running(.+?)\\. If no install process is active, remove the stale lock at (.+?) and retry\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"cli/src/install-store.ts","lineNumber":181,"sourceCode":"    const temporaryPath = `${paths.lockPath}.${token}.tmp`;\n    try {\n      fs.writeFileSync(temporaryPath, `${token}\\n`, { mode: 0o600, flag: \"wx\" });\n      try {\n        fs.linkSync(temporaryPath, paths.lockPath);\n        return;\n      } catch (error) {\n        if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n      }\n      const owner = fs.readFileSync(paths.lockPath, \"utf8\").trim();\n      const ownerPid = Number.parseInt(owner.split(\":\", 1)[0] ?? \"\", 10);\n      if (Number.isInteger(ownerPid) && ownerPid > 0 && !processIsAlive(ownerPid)) {\n        fs.rmSync(paths.lockPath);\n        fs.rmSync(temporaryPath, { force: true });\n        acquire();\n        return;\n      }\n      const ownerLabel = Number.isInteger(ownerPid) && ownerPid > 0 ? ` (pid ${ownerPid})` : \"\";\n      throw new Error(\n        `Another managed install is already running${ownerLabel}. ` +\n        `If no install process is active, remove the stale lock at ${paths.lockPath} and retry.`,\n      );\n    } finally {\n      fs.rmSync(temporaryPath, { force: true });\n    }\n  };\n\n  acquire();\n  try {\n    return await callback();\n  } finally {\n    try {\n      if (fs.readFileSync(paths.lockPath, \"utf8\").trim() === token) {\n        fs.rmSync(paths.lockPath, { force: true });\n      }\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/install-store.ts#L163-L199","documentation":"Thrown by withInstallStoreLock() when the install lock file (.install.lock) is held and the owning PID is still alive (process.kill(pid,0) succeeds or returns EPERM, meaning the process exists). The library auto-recovers stale locks (dead owner) but refuses to steal a lock from a live process. The message includes the owner PID when parseable and tells the user exactly which lock file to remove if they are sure no install is running.","triggerScenarios":"Called withInstallStoreLock() while another process holds the lock: linkSync(temporaryPath, lockPath) returned EEXIST, the owner PID read from the lock is a positive integer, and processIsAlive(ownerPid) returned true (process exists).","commonSituations":"1) Two concurrent 'paperclipai install' invocations. 2) A previous install is still running in another terminal or CI step. 3) A long-running install hung without exiting. 4) A background scheduler kicked off a second install before the first finished.","solutions":["Wait for the other install (pid shown in the message) to finish, then retry.","Confirm via 'ps -p <pid>' whether the owner is genuinely an install process; if it is hung, kill it ('kill <pid>').","If no install is actually running (lock is stale but PID was reused by an unrelated live process), remove the lock file at the path shown and retry.","Serialize install invocations with a higher-level lock or queue to avoid concurrent runs."],"exampleFix":"$ paperclipai install\nError: Another managed install is already running (pid 12345)...\n$ ps -p 12345   # confirm if real install\n$ kill 12345    # if hung\n$ rm ~/.paperclip/cli/.install.lock\n$ paperclipai install","handlingStrategy":"retry","validationCode":"import fs from \"node:fs\";\nimport { resolveInstallStorePaths } from \"./install-store.js\";\n\nfunction isLockHeldByLiveProcess(paths = resolveInstallStorePaths()): boolean {\n  try {\n    const owner = fs.readFileSync(paths.lockPath, \"utf8\").trim();\n    const pid = Number.parseInt(owner.split(\":\", 1)[0] ?? \"\", 10);\n    if (!Number.isInteger(pid) || pid <= 0) return true; // unknown owner → treat as held\n    try { process.kill(pid, 0); return true; }\n    catch (e) { return (e as NodeJS.ErrnoException).code === \"EPERM\"; }\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await withInstallStoreLock(doInstall, paths);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Another managed install is already running\")) {\n    // Option A: wait and retry. Option B: surface to user with the PID + lock path.\n    console.error(err.message);\n    process.exit(1);\n  }\n  throw err;\n}","preventionTips":["Serialize install commands — do not run two 'paperclipai install' concurrently.","In CI, ensure the previous install step fully exited before starting the next.","If an install hangs, kill the owning PID before removing the lock file manually.","Do not delete .install.lock while a real install is running."],"tags":["install-store","concurrency","lock","cli"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}