paperclipai/paperclip · error

Refusing to use unsafe shim directory

Error message

Refusing to use unsafe shim directory ${directoryPath}.

What it means

assertManagedShimWritable checks the ~/.local/bin chain and found a non-directory or symlink where a directory is expected; the guard refuses to write the shim through unsafe paths.

Solutions

  1. Use a shim directory owned by the current user and not a symlink: ${directoryPath}.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at cli/src/install-store.ts:357 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/716d4f548043ef58. Report an issue: GitHub.

Appendix: source

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

    for (const entry of fs.readdirSync(sourceRoot)) {
      if (entry.startsWith(".")) continue;
      const candidate = path.join(sourceRoot, entry);
      if (!retained.has(path.resolve(candidate))) {
        fs.rmSync(candidate, { recursive: true, force: true });
        removed.push(candidate);
      }
    }
  }
  return removed;
}

export function assertManagedShimWritable(paths = resolveInstallStorePaths()): void {
  const homeDir = path.dirname(path.dirname(path.dirname(paths.shimPath)));
  for (const directoryPath of [homeDir, path.join(homeDir, ".local"), path.dirname(paths.shimPath)]) {
    if (!fs.existsSync(directoryPath)) continue;
    const directoryStat = fs.lstatSync(directoryPath);
    if (!directoryStat.isDirectory() || directoryStat.isSymbolicLink()) {
      throw new Error(`Refusing to use unsafe shim directory ${directoryPath}.`);
    }
    assertOwnedByCurrentUser(directoryStat, directoryPath);
  }
  try {
    const stat = fs.lstatSync(paths.shimPath);
    if (!stat.isFile() || stat.isSymbolicLink()) {
      throw new Error(`Refusing to replace non-regular shim ${paths.shimPath}.`);
    }
    assertOwnedByCurrentUser(stat, paths.shimPath);
    if (stat.nlink > 1) throw new Error(`Refusing to replace multiply linked shim ${paths.shimPath}.`);
    const existing = fs.readFileSync(paths.shimPath, "utf8");
    if (!isManagedShimContents(existing)) {
      throw new Error(`Refusing to replace existing non-managed command ${paths.shimPath}.`);
    }
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
  }
}

View on GitHub (pinned to 01ad858492)