paperclipai/paperclip · error

Refusing to replace non-symlink

Error message

Refusing to replace non-symlink ${paths.currentPath}.

What it means

flipCurrentAtomic found an existing entry at the 'current' path that is not a symlink; it only ever atomically replaces a symlink and refuses to delete other file types.

Solutions

  1. Remove the non-symlink at ${paths.currentPath} manually after verifying it is safe, then retry.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at cli/src/install-store.ts:273 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-08-18). Data as JSON: /api/errors/85375cdf4c62551c. Report an issue: GitHub.

Appendix: source

Thrown at cli/src/install-store.ts:273

  }
  const installsRealPath = fs.realpathSync(paths.installsRoot);
  const payloadRealPath = fs.realpathSync(payloadPath);
  if (!payloadRealPath.startsWith(`${installsRealPath}${path.sep}`)) {
    throw new Error(`Refusing to activate payload that resolves outside ${paths.installsRoot}.`);
  }
}

export function flipCurrentAtomic(
  payloadPath: string,
  paths = resolveInstallStorePaths(),
  hooks: { beforeRename?: () => void } = {},
): void {
  assertPayloadPath(payloadPath, paths);
  ensurePrivateDirectory(paths.cliRoot);
  try {
    const currentStat = fs.lstatSync(paths.currentPath);
    if (!currentStat.isSymbolicLink()) {
      throw new Error(`Refusing to replace non-symlink ${paths.currentPath}.`);
    }
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
  }

  const temporaryLink = path.join(
    paths.cliRoot,
    `.current-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`,
  );
  const relativeTarget = path.relative(paths.cliRoot, payloadPath);
  try {
    fs.symlinkSync(relativeTarget, temporaryLink, "dir");
    hooks.beforeRename?.();
    fs.renameSync(temporaryLink, paths.currentPath);
  } finally {
    fs.rmSync(temporaryLink, { force: true });
  }
}

View on GitHub (pinned to 01ad858492)