paperclipai/paperclip · error · Error

Another restart for instance

Error message

Another restart for instance ${instanceId} is still running. If no restart process is active, remove the stale lock at ${lockPath} and retry.

What it means

withHotRestartLock uses an exclusive lockfile per instance; another live restart process holds it. A stale lock whose owner pid is dead is auto-removed, so seeing this means the owner is alive or the lock is manually stuck.

Solutions

  1. Wait for the running restart to finish; if none is active, remove the stale lock file and retry.
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at cli/src/commands/service.ts:97 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18). Data as JSON: /api/errors/6c20fd0d45712c6b. Report an issue: GitHub.

Appendix: source

Thrown at cli/src/commands/service.ts:97

      await fs.writeFile(lockPath, `${token}\n`, { encoding: "utf8", mode: 0o600, flag: "wx" });
      break;
    } catch (error) {
      if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
      try {
        const existingToken = (await fs.readFile(lockPath, "utf8")).trim();
        const ownerPid = Number.parseInt(existingToken.split(":", 1)[0] ?? "", 10);
        if (Number.isInteger(ownerPid) && ownerPid > 0 && !isProcessAlive(ownerPid)) {
          if ((await fs.readFile(lockPath, "utf8")).trim() === existingToken) {
            await fs.rm(lockPath, { force: true });
            continue;
          }
        }
      } catch (readError) {
        if ((readError as NodeJS.ErrnoException).code === "ENOENT") continue;
        throw readError;
      }
      if (Date.now() >= deadline) {
        throw new Error(
          `Another restart for instance ${instanceId} is still running. ` +
          `If no restart process is active, remove the stale lock at ${lockPath} and retry.`,
        );
      }
      await new Promise((resolve) => setTimeout(resolve, pollMs));
    }
  }

  try {
    return await callback();
  } finally {
    try {
      if ((await fs.readFile(lockPath, "utf8")).trim() === token) {
        await fs.rm(lockPath, { force: true });
      }
    } catch (error) {
      if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
    }

View on GitHub (pinned to 120ae5428f)