paperclipai/paperclip · error
Refusing to replace existing non-managed command
Error message
Refusing to replace existing non-managed command ${paths.shimPath}. What it means
The shim path is occupied by a file that does not contain the managed marker content, i.e. some other tool's binary; the guard refuses to clobber non-managed commands.
Solutions
- Rename or remove the existing non-managed command at ${paths.shimPath}, then retry.
- Choose a different shim name or directory.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at cli/src/install-store.ts:370 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/be6e30d60cb4839c.
Report an issue: GitHub.
Appendix: source
Thrown at cli/src/install-store.ts:370
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;
}
}
function shellQuote(value: string): string {
return `'${value.replace(/'/g, `'"'"'`)}'`;
}
function isManagedShimContents(contents: string): boolean {
const lines = contents.split("\n");
// Accept the original pinned-runtime shim so upgrades can replace it.
const withRuntimePath = lines.length === 6;
const execIndex = withRuntimePath ? 4 : 3;
return (
(lines.length === 5 || withRuntimePath) &&
lines[0] === "#!/bin/sh" &&View on GitHub (pinned to 01ad858492)